From 13215f84f48e5b415ec3c05756dd92480d8d778e Mon Sep 17 00:00:00 2001 From: Nick <1528282042@qq.com> Date: Tue, 2 Jun 2020 21:16:37 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B3=A8=E9=87=8A=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../modules/security/rest/AuthController.java | 9 +++++++-- .../modules/security/security/TokenFilter.java | 2 +- .../security/security/TokenProvider.java | 14 ++++++++++++++ .../security/service/OnlineUserService.java | 17 +++++++++++++++++ 4 files changed, 39 insertions(+), 3 deletions(-) diff --git a/eladmin-system/src/main/java/me/zhengjie/modules/security/rest/AuthController.java b/eladmin-system/src/main/java/me/zhengjie/modules/security/rest/AuthController.java index 5822720e..15500b76 100644 --- a/eladmin-system/src/main/java/me/zhengjie/modules/security/rest/AuthController.java +++ b/eladmin-system/src/main/java/me/zhengjie/modules/security/rest/AuthController.java @@ -49,7 +49,7 @@ public class AuthController { private Long expiration; @Value("${rsa.private_key}") private String privateKey; - @Value("${single.login:false}") + @Value("${single.login:true}") private Boolean singleLogin; /** * 对于final类型的属性,并且构造函数有包含它们的话,那么就不需要写AutoWired注解,Spring4.3之后会自动注入; @@ -98,12 +98,16 @@ public class AuthController { * 这是一个Authentication对象;,principal存储用户名,credentials存储密码, * 然后将authenticationToken对象提交到SpringSecurity去验证authenticate(authenticationToken) * 可通过boolean isAuthenticated()方法来决定该Authentication是否认证成功 + * + * UsernamePasswordAuthenticationToken继承AbstractAuthenticationToken, + * AbstractAuthenticationToken实现Authentication和CredentialsContainer + * 其中的CredentialsContainer接口会在擦除Credentials字段的值的时候使用到 */ UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(authUser.getUsername(), password); /** * 通过token获得授权对象 - * + * 链式执行到ProviderManager的最后,会将已验证的对象的Credentials字段的值进行擦除 */ Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken); SecurityContextHolder.getContext().setAuthentication(authentication); @@ -117,6 +121,7 @@ public class AuthController { put("token", properties.getTokenStartWith() + token); put("user", jwtUser); }}; + //不同的浏览器中总共只允许此账号登陆一次 if(singleLogin){ //踢掉之前已经登录的token onlineUserService.checkLoginOnUser(authUser.getUsername(),token); diff --git a/eladmin-system/src/main/java/me/zhengjie/modules/security/security/TokenFilter.java b/eladmin-system/src/main/java/me/zhengjie/modules/security/security/TokenFilter.java index f14068ec..b994894e 100644 --- a/eladmin-system/src/main/java/me/zhengjie/modules/security/security/TokenFilter.java +++ b/eladmin-system/src/main/java/me/zhengjie/modules/security/security/TokenFilter.java @@ -54,7 +54,7 @@ public class TokenFilter extends GenericFilterBean { } /** - * + * 如果redis存在这个用户(通过redis.getKey()是否为null来判断),并且request中的token不为空且token能被正确解析 */ if (onlineUser != null && StringUtils.hasText(token) && tokenProvider.validateToken(token)) { Authentication authentication = tokenProvider.getAuthentication(token); diff --git a/eladmin-system/src/main/java/me/zhengjie/modules/security/security/TokenProvider.java b/eladmin-system/src/main/java/me/zhengjie/modules/security/security/TokenProvider.java index 24240128..893175c7 100644 --- a/eladmin-system/src/main/java/me/zhengjie/modules/security/security/TokenProvider.java +++ b/eladmin-system/src/main/java/me/zhengjie/modules/security/security/TokenProvider.java @@ -56,6 +56,20 @@ public class TokenProvider implements InitializingBean { Date validity = new Date(now + properties.getTokenValidityInSeconds()); /** * 使用HmacSHA512加密 + * + * compact()将一个JwtBuilder对象DefaultJwtBuilder序列化为一个字符串 + * signWith()使用特定的加密算法和秘钥对JWT进行加密 + * setSubject()可选声明 + * + * 一个JWT由三部分组成: + * + * header(头部)-----base64编码的Json字符串,可以不使用setHeader()方法,也会自己设置的 + * + * Payload(载荷)---base64编码的Json字符串,claim()设置载荷,具体是JWT中保存重点信息的那一段 + * + * Signature(签名)---使用指定算法,通过Header和Playload加盐计算的字符串 + * + * 各部分以“.”分割 */ return Jwts.builder() .setSubject(authentication.getName()) diff --git a/eladmin-system/src/main/java/me/zhengjie/modules/security/service/OnlineUserService.java b/eladmin-system/src/main/java/me/zhengjie/modules/security/service/OnlineUserService.java index cc568f00..eb532020 100644 --- a/eladmin-system/src/main/java/me/zhengjie/modules/security/service/OnlineUserService.java +++ b/eladmin-system/src/main/java/me/zhengjie/modules/security/service/OnlineUserService.java @@ -41,6 +41,9 @@ public class OnlineUserService { String address = StringUtils.getCityInfo(ip); OnlineUser onlineUser = null; try { + /** + * 注意,这里对登录用户的token进行了加密 + */ onlineUser = new OnlineUser(jwtUser.getUsername(), jwtUser.getNickName(), job, browser , ip, address, EncryptUtils.desEncrypt(token), new Date()); } catch (Exception e) { e.printStackTrace(); @@ -68,11 +71,22 @@ public class OnlineUserService { * @return / */ public List getAll(String filter){ + /** + * 根据redis中存在的key得到对应的value在强制转换成OnlineUser + */ List keys = redisUtils.scan(properties.getOnlineKey() + "*"); Collections.reverse(keys); List onlineUsers = new ArrayList<>(); for (String key : keys) { OnlineUser onlineUser = (OnlineUser) redisUtils.get(key); + /* 这里我觉得应该是为了测试需要,实际项目中只有admin用户才能获取全部用户的在线信息 + if(StringUtils.isNotBlank(filter)){ + if(onlineUser.toString().contains("admin")) { + onlineUsers.add(onlineUser); + } else if(onlineUser.toString().contains(filter)){ + onlineUsers.add(onlineUser); + } + }*/ if(StringUtils.isNotBlank(filter)){ if(onlineUser.toString().contains(filter)){ onlineUsers.add(onlineUser); @@ -139,6 +153,9 @@ public class OnlineUserService { * @param userName 用户名 */ public void checkLoginOnUser(String userName, String igoreToken){ + /** + * 查询全部的已登录的用户 + */ List onlineUsers = getAll(userName); if(onlineUsers ==null || onlineUsers.isEmpty()){ return;