Explorar o código

重复用户登录

xusl %!s(int64=2) %!d(string=hai) anos
pai
achega
ba731bf203

+ 9 - 1
backend/src/main/java/com/jiayue/ssi/constant/CacheConstants.java

@@ -1,5 +1,10 @@
 package com.jiayue.ssi.constant;
 
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
 /**
  * 缓存的key 常量
  *
@@ -46,5 +51,8 @@ public class CacheConstants
      * 登录账户密码错误次数 redis key
      */
     public static final String PWD_ERR_CNT_KEY = "pwd_err_cnt:";
-
+    /**
+     * 登录token存储,map<用户名,token:授权时间>
+     */
+    public static final Map<String,String> LOGIN_TOKEN_MAP = new ConcurrentHashMap<String,String>();
 }

+ 20 - 0
backend/src/main/java/com/jiayue/ssi/filter/JwtAuthenticationTokenFilter.java

@@ -1,13 +1,16 @@
 package com.jiayue.ssi.filter;
 
 import java.io.IOException;
+import java.util.Date;
 
 import javax.servlet.FilterChain;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import com.jiayue.ssi.constant.CacheConstants;
 import com.jiayue.ssi.service.impl.UserServiceImpl;
+import com.jiayue.ssi.util.ResponseInfo;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.core.annotation.Order;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
@@ -42,6 +45,21 @@ public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
         String token = request.getHeader("Authorization");
         if (!StringUtils.isEmpty(token)) {
             String username = jwtTokenUtil.getUsernameFromToken(token);
+            if (username != null){
+                if (CacheConstants.LOGIN_TOKEN_MAP.get(username)==null){
+                    ResponseInfo.doResponse(response, "服务器端无此token令牌,请重新登录!", 403);
+                    return;
+                }
+                else{
+                    String cacheToken = CacheConstants.LOGIN_TOKEN_MAP.get(username);
+                    //内存token和当前token一致  说明是当前登陆用户访问
+                    if(!token.equals(cacheToken)){
+                        ResponseInfo.doResponse(response, "账号已在另一台机器登录,请重新登录!", 403);
+                        return;
+                    }
+                }
+            }
+
             if (username != null && SecurityContextHolder.getContext().getAuthentication() == null){
                 UserDetails userDetails = userServiceImpl.loadUserByUsername(username);
                 if (jwtTokenUtil.validateToken(token, userDetails)){
@@ -56,4 +74,6 @@ public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
         }
         chain.doFilter(request, response);
     }
+
+
 }

+ 1 - 1
backend/src/main/java/com/jiayue/ssi/filter/VerifySmFilter.java

@@ -53,7 +53,7 @@ public class VerifySmFilter extends OncePerRequestFilter {
                     }
                     JwtTokenUtil jwtTokenUtil = new JwtTokenUtil();
                     if (jwtTokenUtil.isTokenExpired(decryptTokenStr)) {
-                        ResponseInfo.doResponse(response, "登录超时,请重新登录!", 403);
+                        ResponseInfo.doResponse(response, "token令牌无效,请重新登录!", 403);
                         return;
                     }
 

+ 13 - 2
backend/src/main/java/com/jiayue/ssi/handler/CustomAuthenticationFailureHandler.java

@@ -41,9 +41,20 @@ public class CustomAuthenticationFailureHandler extends SimpleUrlAuthenticationF
         }
         else {
             // 失败总次数
-            int errCount = Integer.parseInt(sysParameterService.queryByKey("errCount","5"));
+            int errCount = 5;
+            try {
+                errCount = Integer.parseInt(sysParameterService.queryByKey("errCount", "5"));
+            } catch (Exception errCountErr) {
+                // 日志输出转换失败的提示
+            }
+            int lockedTime = 1200000;
+            try {
+                lockedTime = Integer.parseInt(sysParameterService.queryByKey("lockedTime", "1200000"));
+            } catch (Exception lockedTimeErr) {
+                // 日志输出转换失败的提示
+            }
             if (user.getStatus().equals("1")) {
-                Long xz = (user.getLockTime() + LoginConstants.LOGIN_LOCK - System.currentTimeMillis()) / 1000;
+                Long xz = (user.getLockTime() + lockedTime - System.currentTimeMillis()) / 1000;
                 if (xz < 0) {
                     if (errCount-1==0) {
                         errorTips = "用户锁定,稍后再试";

+ 3 - 0
backend/src/main/java/com/jiayue/ssi/handler/CustomAuthenticationSuccessHandler.java

@@ -51,6 +51,9 @@ public class CustomAuthenticationSuccessHandler extends SavedRequestAwareAuthent
 
         SecurityContextHolder.getContext().setAuthentication(authentication);
         String token = jwtTokenUtil.generateToken(sysUser);
+        // 将token存储内存中,便于重复登录比对
+        CacheConstants.LOGIN_TOKEN_MAP.put(username,token);
+
         String obj = JSONUtil.toJsonStr(ResponseVO.success(token));
         // token加密处理
         String encrypt = SM2CryptUtils.encrypt(obj, SecretKeyConstants.CLIENT_PUBLIC_KEY);

+ 1 - 1
backend/src/main/java/com/jiayue/ssi/interceptor/TokenStatusInterceptor.java

@@ -29,7 +29,7 @@ public class TokenStatusInterceptor implements HandlerInterceptor {
         Claims claims = jwtTokenUtil.getClaimsFromToken(token);
         // 获取失效时间
         long expirationTime = claims.getExpiration().getTime();
-        if (System.currentTimeMillis()>(expirationTime-(1000*60*4+40000))){
+        if (System.currentTimeMillis()>(expirationTime-(1000*60*4))){
             // 刷新token
             ResponseInfo.doResponse(response,"token即将失效,需要刷新!",409);
             return false;

+ 12 - 4
backend/src/main/java/com/jiayue/ssi/service/impl/UserServiceImpl.java

@@ -1,6 +1,7 @@
 package com.jiayue.ssi.service.impl;
 
 import com.jiayue.ssi.constant.LoginConstants;
+import com.jiayue.ssi.service.SysParameterService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.core.authority.AuthorityUtils;
 import org.springframework.security.core.userdetails.User;
@@ -23,15 +24,22 @@ import com.jiayue.ssi.mapper.SysUserMapper;
 public class UserServiceImpl implements UserDetailsService {
     @Autowired
     SysUserMapper sysUserMapper;
+    @Autowired
+    SysParameterService sysParameterService;
 
     @Override
     public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
-        SysUser sysUser = sysUserMapper.selectOne(new QueryWrapper<SysUser>().eq("username",username));
+        SysUser sysUser = sysUserMapper.selectOne(new QueryWrapper<SysUser>().eq("username", username));
         if (sysUser == null) {
             throw new UsernameNotFoundException("用户名错误!");
-        }
-        else{
-            if (sysUser.getStatus().equals("1") && (System.currentTimeMillis() - sysUser.getLockTime()) < LoginConstants.LOGIN_LOCK) {
+        } else {
+            int lockedTime = 1200000;
+            try {
+                lockedTime = Integer.parseInt(sysParameterService.queryByKey("lockedTime", "1200000"));
+            } catch (Exception e) {
+                // 日志输出转换失败的提示
+            }
+            if (sysUser.getStatus().equals("1") && (System.currentTimeMillis() - sysUser.getLockTime()) < lockedTime) {
                 sysUser.setPassword("1");
             }
             if (sysUser.getStatus().equals("2")) {

+ 14 - 7
backend/src/main/java/com/jiayue/ssi/util/JwtTokenUtil.java

@@ -1,12 +1,14 @@
 package com.jiayue.ssi.util;
 
 
+import cn.hutool.core.date.DateUtil;
 import com.jiayue.ssi.entity.SysUser;
 import io.jsonwebtoken.*;
 import lombok.Data;
 import org.springframework.security.core.userdetails.UserDetails;
 import org.springframework.stereotype.Component;
 
+import java.text.SimpleDateFormat;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.Map;
@@ -23,7 +25,7 @@ public class JwtTokenUtil {
     private String secret = "jiayue";
 
     /**
-     * 过期时长(毫秒)
+     * 过期时长30分钟(毫秒)
      */
     private Long expiration = 1800000L;
 
@@ -37,7 +39,7 @@ public class JwtTokenUtil {
      */
     private String generateToken(Map<String, Object> claims) {
         Date expirationDate = new Date(System.currentTimeMillis() + expiration);
-        return Jwts.builder().setClaims(claims).setExpiration(expirationDate).signWith(SignatureAlgorithm.HS512, secret).compact();
+        return Jwts.builder().setClaims(claims).setExpiration(expirationDate).setIssuedAt(new Date(System.currentTimeMillis())).signWith(SignatureAlgorithm.HS512, secret).compact();
     }
 
     /**
@@ -148,17 +150,22 @@ public class JwtTokenUtil {
         System.out.println("jwt body user-id:" + body.get("user_id", String.class));
     }
 
-    public static void main(String[] args) {
+    public static void main(String[] args)throws Exception {
         JwtTokenUtil jwtTokenUtil = new JwtTokenUtil();
         Map<String, Object> claims = new HashMap<String, Object>(16);
         claims.put(Claims.SUBJECT, "Test");
-        claims.put(Claims.ISSUED_AT, new Date());
+//        claims.put(Claims.ISSUED_AT, new Date(System.currentTimeMillis()));
         String token=jwtTokenUtil.generateToken(claims);
         System.out.println(jwtTokenUtil.getUsernameFromToken(token));
         System.out.println(jwtTokenUtil.isTokenExpired(token));
         Claims claims1 = jwtTokenUtil.getClaimsFromToken(token);
-        System.out.println("过期时间:"+claims1.getExpiration());
-        System.out.println("过期时间提前2分钟:"+new Date(claims1.getExpiration().getTime()-1000*60*2));
-
+//        System.out.println("过期时间:"+claims1.getExpiration());
+//        System.out.println("过期时间提前2分钟:"+new Date(claims1.getExpiration().getTime()-1000*60*2));
+//        Thread.sleep(3000L);
+        System.out.println(token);
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        System.out.println("签发时间:"+ sdf.format(claims1.getIssuedAt()));
+// eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJUZXN0IiwiZXhwIjoxNjc5MzA0MTUyLCJpYXQiOjE2NzkzMDIzNTJ9.Mtv8qJHbjLdnf52VRodqYqp1B2RI1iB_SxzIO92QccwmshQasJOqQL_rhRhgHFcwZRkUmfdwPy06UsWEr3zZ7w
+// eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJUZXN0IiwiZXhwIjoxNjc5MzA0MTY5LCJpYXQiOjE2NzkzMDIzNjl9.x0CiNFezdegvRzmFSQyCzzmNrA-N5g4QaHMZOQubThx6LIOFM8jkoPJgEWc8xUlUipTW5CqFKfxn0z0O0xVvoQ
     }
 }

+ 1 - 1
ui/src/main.js

@@ -184,7 +184,7 @@ Vue.prototype.$axios.interceptors.response.use(
           resetRouter()
           router.push('/login')
           Message({
-            message: '登录超时',
+            message: error.response.data,
             type: 'error',
             duration: 5 * 1000
           })

+ 3 - 3
ui/src/views/sysManager/sysParameter/index.vue

@@ -172,7 +172,7 @@ export default {
         }
         this.loading = false
       }).catch((error) => {
-        this.$message.error('获取数据出错' + error)
+        // this.$message.error('获取数据出错' + error)
       })
     },1000),
     handlePageChange({ currentPage, pageSize }) {
@@ -204,7 +204,7 @@ export default {
               this.saveLoding = false
               this.getList();
             }).catch((error) => {
-              this.$message.error(error)
+              // this.$message.error(error)
               this.saveLoding = false
             })
           } else {
@@ -219,7 +219,7 @@ export default {
               this.saveLoding = false
               this.btnLonding = false
             }).catch((error) => {
-              this.$message.error(error)
+              // this.$message.error(error)
               this.saveLoding = false
             })
           }

+ 3 - 3
ui/src/views/sysManager/userManager/index.vue

@@ -305,7 +305,7 @@ export default {
         }
         this.loading = false
       }).catch((error) => {
-        this.$message.error('获取数据出错' + error)
+        // this.$message.error(error)
       })
     },1000),
     // 用户状态修改
@@ -372,7 +372,7 @@ export default {
               }
               this.loading = false
             }).catch((error) => {
-              this.$message.error(error)
+              // this.$message.error(error)
               this.loading = false
             })
           } else {
@@ -394,7 +394,7 @@ export default {
               }
               this.loading = false
             }).catch((error) => {
-              this.$message.error(error)
+              // this.$message.error(error)
               this.loading = false
             })
           }

+ 1 - 1
ui/src/views/sysManager/userManager/profile/resetPwd.vue

@@ -133,7 +133,7 @@ export default {
               this.$message.error(res.data)
             }
           }).catch((error) => {
-            this.$message.error(error)
+            // this.$message.error(error)
           })
         }
       });