Commit 00762fb4f483df1c1c9d5fa9abf3116efe84b3ab

Authored by Liu Haoyu
1 parent 68a67f36

代码重构;

token添加过期功能;
添加只能一点登录功能;
src/main/java/com/objecteye/config/AuthenticationHeadFilter.java
1 1 package com.objecteye.config;
2 2  
3 3 import com.alibaba.fastjson.JSON;
  4 +import com.objecteye.pojo.AuthenticationToken;
4 5 import com.objecteye.pojo.TokenUser;
  6 +import com.objecteye.utils.GlobalUtil;
  7 +import org.springframework.data.redis.core.RedisTemplate;
5 8 import org.springframework.security.core.context.SecurityContextHolder;
6 9 import org.springframework.security.jwt.Jwt;
7 10 import org.springframework.security.jwt.JwtHelper;
... ... @@ -22,6 +25,12 @@ public class AuthenticationHeadFilter extends OncePerRequestFilter {
22 25  
23 26 private RsaVerifier rsaVerifier;
24 27  
  28 + private RedisTemplate redisTemplate;
  29 +
  30 + public void setRedisTemplate(RedisTemplate redisTemplate) {
  31 + this.redisTemplate = redisTemplate;
  32 + }
  33 +
25 34 public void setRsaVerifier(RsaVerifier rsaVerifier) {
26 35 this.rsaVerifier = rsaVerifier;
27 36 }
... ... @@ -33,12 +42,25 @@ public class AuthenticationHeadFilter extends OncePerRequestFilter {
33 42 filterChain.doFilter(httpServletRequest, httpServletResponse);
34 43 return;
35 44 }
36   -
37 45 TokenUser user;
38 46 try {
39 47 Jwt jwt = JwtHelper.decodeAndVerify(token, rsaVerifier);
40 48 String claims = jwt.getClaims();
41 49 user = JSON.parseObject(claims, TokenUser.class);
  50 + // 是否单点登录
  51 + Long createTime = user.getCreateTime();
  52 + Long tokenCreateTime = (Long) redisTemplate.opsForHash().get(GlobalUtil.LOGIN_USER_TOKEN, user.getUsername());
  53 + if (!createTime.equals(tokenCreateTime)) {
  54 + httpServletResponse.setContentType("application/json;charset=UTF-8");
  55 + httpServletResponse.getWriter().write("用户已在其他地方登录");
  56 + return;
  57 + }
  58 + // 是否超时(默认1小时)
  59 + if (System.currentTimeMillis() > createTime + 1000 * 60 * 60) {
  60 + httpServletResponse.setContentType("application/json;charset=UTF-8");
  61 + httpServletResponse.getWriter().write("Token已过期请重新登录");
  62 + return;
  63 + }
42 64 } catch (Exception e) {
43 65 e.printStackTrace();
44 66 httpServletResponse.setContentType("application/json;charset=UTF-8");
... ...
src/main/java/com/objecteye/config/AuthenticationLoginFilter.java
1 1 package com.objecteye.config;
2 2  
  3 +import com.objecteye.pojo.AuthenticationToken;
3 4 import org.springframework.security.core.Authentication;
4 5 import org.springframework.security.core.AuthenticationException;
5 6 import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
... ...
src/main/java/com/objecteye/config/AuthenticationProviderConfig.java
1 1 package com.objecteye.config;
2 2  
  3 +import com.objecteye.pojo.AuthenticationToken;
3 4 import org.springframework.security.authentication.*;
4 5 import org.springframework.security.core.Authentication;
5 6 import org.springframework.security.core.AuthenticationException;
... ...
src/main/java/com/objecteye/config/WebSecurityConfig.java
1 1 package com.objecteye.config;
2 2  
3 3 import com.objecteye.common.ResultCode;
  4 +import com.objecteye.handle.LoginFailureHandler;
  5 +import com.objecteye.handle.LoginSuccessHandler;
4 6 import com.objecteye.service.impl.UserDetailServiceImpl;
5 7 import org.springframework.beans.factory.annotation.Autowired;
6 8 import org.springframework.context.annotation.Bean;
7 9 import org.springframework.context.annotation.Configuration;
  10 +import org.springframework.data.redis.core.RedisTemplate;
8 11 import org.springframework.security.config.annotation.web.builders.HttpSecurity;
9 12 import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
10 13 import org.springframework.security.config.http.SessionCreationPolicy;
... ... @@ -26,6 +29,9 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
26 29 @Autowired
27 30 private UserDetailServiceImpl userDetailService;
28 31  
  32 + @Autowired
  33 + private RedisTemplate redisTemplate;
  34 +
29 35 @Override
30 36 protected void configure(HttpSecurity http) throws Exception {
31 37 AuthenticationLoginFilter authenticationLoginFilter = new AuthenticationLoginFilter();
... ... @@ -33,6 +39,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
33 39  
34 40 LoginSuccessHandler loginSuccessHandler = new LoginSuccessHandler();
35 41 loginSuccessHandler.setSigner(signer);
  42 + loginSuccessHandler.setRedisTemplate(redisTemplate);
36 43 authenticationLoginFilter.setAuthenticationSuccessHandler(loginSuccessHandler);
37 44 authenticationLoginFilter.setAuthenticationFailureHandler(new LoginFailureHandler());
38 45  
... ... @@ -42,6 +49,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
42 49  
43 50 AuthenticationHeadFilter headFilter = new AuthenticationHeadFilter();
44 51 headFilter.setRsaVerifier(verifier);
  52 + headFilter.setRedisTemplate(redisTemplate);
45 53  
46 54 http.exceptionHandling().authenticationEntryPoint((request, response, authException) -> {
47 55 response.setContentType("application/json;charset=UTF-8");
... ...
src/main/java/com/objecteye/controller/UserController.java
... ... @@ -4,6 +4,7 @@ import com.objecteye.common.CommonResult;
4 4 import com.objecteye.service.UserServices;
5 5 import com.objecteye.utils.GlobalUtil;
6 6 import org.springframework.beans.factory.annotation.Autowired;
  7 +import org.springframework.security.core.context.SecurityContextHolder;
7 8 import org.springframework.web.bind.annotation.*;
8 9  
9 10 import java.util.Map;
... ... @@ -16,6 +17,11 @@ public class UserController extends BasicController {
16 17 @Autowired
17 18 public UserServices userServices;
18 19  
  20 + @RequestMapping(value = "whoami", method = RequestMethod.POST, produces = GlobalUtil.COMMON_HEADER_CONTENT_TYPE)
  21 + public CommonResult whoAmI() {
  22 + return CommonResult.success(SecurityContextHolder.getContext().getAuthentication().getPrincipal());
  23 + }
  24 +
19 25 @RequestMapping(value = "checkUser", method = RequestMethod.POST, produces = GlobalUtil.COMMON_HEADER_CONTENT_TYPE)
20 26 public CommonResult checkUser(@RequestBody Map<String, Object> requestMap) {
21 27 return jsonObjectResultHandle(userServices.checkUser(requestMap));
... ...
src/main/java/com/objecteye/config/LoginFailureHandler.java renamed to src/main/java/com/objecteye/handle/LoginFailureHandler.java
1   -package com.objecteye.config;
  1 +package com.objecteye.handle;
2 2  
3 3 import org.springframework.security.core.AuthenticationException;
4 4 import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
... ...
src/main/java/com/objecteye/config/LoginSuccessHandler.java renamed to src/main/java/com/objecteye/handle/LoginSuccessHandler.java
1   -package com.objecteye.config;
  1 +package com.objecteye.handle;
2 2  
3 3 import com.alibaba.fastjson.JSON;
  4 +import com.alibaba.fastjson.JSONObject;
  5 +import com.objecteye.utils.GlobalUtil;
  6 +import org.springframework.data.redis.core.RedisTemplate;
4 7 import org.springframework.security.core.Authentication;
5 8 import org.springframework.security.jwt.JwtHelper;
6 9 import org.springframework.security.jwt.crypto.sign.RsaSigner;
... ... @@ -17,10 +20,15 @@ public class LoginSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
17 20  
18 21 private RsaSigner signer;
19 22  
  23 + private RedisTemplate redisTemplate;
  24 +
20 25 @Override
21 26 public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {
22 27 response.setContentType("application/json;charset=UTF-8");
23 28 String userJsonStr = JSON.toJSONString(authentication.getPrincipal());
  29 + JSONObject userJson = JSON.parseObject(userJsonStr);
  30 + // 保存登录存根
  31 + redisTemplate.opsForHash().put(GlobalUtil.LOGIN_USER_TOKEN, userJson.getString("username"), userJson.getLongValue("createTime"));
24 32 String token = JwtHelper.encode(userJsonStr, signer).getEncoded();
25 33 //签发token
26 34 response.getWriter().write("token=" + token);
... ... @@ -29,4 +37,8 @@ public class LoginSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
29 37 public void setSigner(RsaSigner signer) {
30 38 this.signer = signer;
31 39 }
  40 +
  41 + public void setRedisTemplate(RedisTemplate redisTemplate) {
  42 + this.redisTemplate = redisTemplate;
  43 + }
32 44 }
... ...
src/main/java/com/objecteye/config/AuthenticationToken.java renamed to src/main/java/com/objecteye/pojo/AuthenticationToken.java
1   -package com.objecteye.config;
  1 +package com.objecteye.pojo;
2 2  
3 3 import org.springframework.security.authentication.AbstractAuthenticationToken;
4 4 import org.springframework.security.core.GrantedAuthority;
... ...
src/main/java/com/objecteye/pojo/TokenUser.java
... ... @@ -17,11 +17,14 @@ public class TokenUser implements UserDetails {
17 17  
18 18 private String password;
19 19  
  20 + private Long createTime;
  21 +
20 22 private List<SimpleGrantedAuthority> simpleGrantedAuthorities;
21 23  
22 24 public TokenUser(String userName, String password, String... roles) {
23 25 this.userName = userName;
24 26 this.password = password;
  27 + this.createTime = System.currentTimeMillis();
25 28 this.simpleGrantedAuthorities = Arrays.stream(roles).map(SimpleGrantedAuthority::new).collect(Collectors.toList());
26 29 }
27 30  
... ... @@ -74,4 +77,12 @@ public class TokenUser implements UserDetails {
74 77 public void setSimpleGrantedAuthorities(List<SimpleGrantedAuthority> simpleGrantedAuthorities) {
75 78 this.simpleGrantedAuthorities = simpleGrantedAuthorities;
76 79 }
  80 +
  81 + public Long getCreateTime() {
  82 + return createTime;
  83 + }
  84 +
  85 + public void setCreateTime(Long createTime) {
  86 + this.createTime = createTime;
  87 + }
77 88 }
... ...
src/main/java/com/objecteye/pojo/UserGroup.java
... ... @@ -25,7 +25,7 @@ public class UserGroup implements Serializable {
25 25 private String groupLevel;
26 26  
27 27 /**
28   - * 父级组织id(根为-1, 备用)
  28 + * 父级组织id(根为-1)
29 29 */
30 30 private String parentCode;
31 31  
... ...
src/main/java/com/objecteye/config/AccessConfirmServiceImpl.java renamed to src/main/java/com/objecteye/service/impl/AccessConfirmServiceImpl.java
1   -package com.objecteye.config;
  1 +package com.objecteye.service.impl;
2 2  
3 3 import com.objecteye.pojo.SpecialAuthenticationUrlConfig;
4 4 import com.objecteye.pojo.UserDetailsMsg;
... ... @@ -28,6 +28,16 @@ public class AccessConfirmServiceImpl {
28 28 private AntPathMatcher antPathMatcher = new AntPathMatcher();
29 29  
30 30 public boolean hasPermission(HttpServletRequest request, Authentication auth) {
  31 + // 不需要权限的接口
  32 + List<String> permitAll = new ArrayList<>();
  33 + permitAll.add("/login");
  34 + permitAll.add("/vehicle/user/addUser");
  35 +
  36 + String requestUri = request.getRequestURI();
  37 + if (permitAll.contains(requestUri)) {
  38 + return true;
  39 + }
  40 +
31 41 // 匿名token不允许访问所有的接口
32 42 if (auth instanceof AnonymousAuthenticationToken) {
33 43 return false;
... ... @@ -36,7 +46,7 @@ public class AccessConfirmServiceImpl {
36 46 UserDetails user = (UserDetails) auth.getPrincipal();
37 47 Map<String, Boolean> specialUrlAccessMap = queryUrlByUserName(user.getUsername());
38 48 for (Map.Entry<String, Boolean> entry : specialUrlAccessMap.entrySet()) {
39   - if (antPathMatcher.match(entry.getKey(), request.getRequestURI())) {
  49 + if (antPathMatcher.match(entry.getKey(), requestUri)) {
40 50 return entry.getValue();
41 51 }
42 52 }
... ...
src/main/java/com/objecteye/service/impl/UserDetailServiceImpl.java
... ... @@ -2,6 +2,7 @@ package com.objecteye.service.impl;
2 2  
3 3 import com.objecteye.pojo.TokenUser;
4 4 import com.objecteye.pojo.UserDetailsMsg;
  5 +import com.objecteye.pojo.UserGroup;
5 6 import org.springframework.beans.factory.annotation.Autowired;
6 7 import org.springframework.data.mongodb.core.MongoTemplate;
7 8 import org.springframework.data.mongodb.core.query.Criteria;
... ... @@ -12,8 +13,6 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException;
12 13 import org.springframework.security.crypto.password.PasswordEncoder;
13 14 import org.springframework.stereotype.Component;
14 15  
15   -import java.util.List;
16   -
17 16 @Component
18 17 public class UserDetailServiceImpl implements UserDetailsService {
19 18  
... ... @@ -29,19 +28,19 @@ public class UserDetailServiceImpl implements UserDetailsService {
29 28  
30 29 @Override
31 30 public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
32   - List<UserDetailsMsg> userDetailsMsgs = mongoTemplate.find(Query.query(Criteria.where("userName").is(s)), UserDetailsMsg.class);
33   -
34   - // admin
35   - UserDetailsMsg superAdminUser = new UserDetailsMsg();
36   - superAdminUser.setUsername("superAdmin");
37   - superAdminUser.setPassword("123456");
38   - superAdminUser.setUserRole("1");
39   - userDetailsMsgs.add(superAdminUser);
40   - if (userDetailsMsgs.size() > 0) {
41   - UserDetailsMsg userDetailsMsg = userDetailsMsgs.get(0);
42   - return new TokenUser(userDetailsMsg.getUsername(), passwordEncoder.encode(userDetailsMsg.getPassword()));
  31 + if ("superAdmin".equals(s)) {
  32 + return new TokenUser("superAdmin", passwordEncoder.encode("123456"), "1");
  33 + }
  34 + UserDetailsMsg userDetailsMsg = mongoTemplate.findOne(Query.query(Criteria.where("username").is(s)), UserDetailsMsg.class);
  35 + if (userDetailsMsg != null) {
  36 + UserGroup userGroup = mongoTemplate.findOne(Query.query(Criteria.where("groupCode").is(userDetailsMsg.getGroup())), UserGroup.class);
  37 + String userRole = userDetailsMsg.getUserRole();
  38 + if (userGroup != null) {
  39 + String groupLevel = userGroup.getGroupLevel();
  40 + userRole = String.valueOf(Math.min(Integer.parseInt(userRole), Integer.parseInt(groupLevel)));
  41 + }
  42 + return new TokenUser(userDetailsMsg.getUsername(), passwordEncoder.encode(userDetailsMsg.getPassword()), userRole);
43 43 }
44   -
45 44 return null;
46 45 }
47 46 }
... ...
src/main/java/com/objecteye/service/impl/UserGroupServiceImpl.java
... ... @@ -66,7 +66,14 @@ public class UserGroupServiceImpl implements IUserGroupService {
66 66 @Override
67 67 public JSONObject addGroup(Map<String, Object> requestMap) {
68 68 UserGroup userGroup = JSON.parseObject(JSON.toJSONString(requestMap), UserGroup.class);
69   - UserGroup lastMaxCodeGroup = mongoTemplate.findOne(new Query().with(Sort.by(Sort.Order.desc("groupCode"))), UserGroup.class);
  69 + // 默认是根组织
  70 + String parentCode = "-1";
  71 + if (userGroup.getParentCode() != null && !"".equals(userGroup.getParentCode())) {
  72 + parentCode = userGroup.getParentCode();
  73 + }
  74 + UserGroup lastMaxCodeGroup = mongoTemplate
  75 + .findOne(new Query(Criteria.where("parentCode").is(parentCode))
  76 + .with(Sort.by(Sort.Order.desc("groupCode"))).limit(1), UserGroup.class);
70 77 if (lastMaxCodeGroup == null) {
71 78 userGroup.setGroupCode("001");
72 79 userGroup.setParentCode("-1");
... ... @@ -81,7 +88,6 @@ public class UserGroupServiceImpl implements IUserGroupService {
81 88 } else {
82 89 resultObj.put("error", "创建失败");
83 90 }
84   -
85 91 return resultObj;
86 92 }
87 93  
... ...
src/main/java/com/objecteye/utils/GlobalUtil.java
... ... @@ -35,6 +35,10 @@ public class GlobalUtil {
35 35 public final static String PREVIEWIPLISTLIST = "previewIpList";
36 36 public final static String ALARMMSG = "alarmMsg";
37 37 public final static String DEPLOYIDANDENDTIME = "deployIdAndTime";
  38 + /**
  39 + * 已经登录的用户token相关信息, hashKey = loginUserToken, key: username, value: login time(long type)
  40 + */
  41 + public final static String LOGIN_USER_TOKEN = "loginUserToken";
38 42  
39 43 public final static String COMMON_HEADER_CONTENT_TYPE = "application/json;charset=UTF-8";
40 44  
... ...