In a distributed environment , How to support PC、APP(ios、android) Such as the multi terminal session sharing , This is the solution that all companies need , In the traditional way session The way to solve , I think it's already out 了 , Can we find a general solution , For example, with tradition cas To realize the multi system sso Single sign on or use oauth Third party login scheme for ? Today, I'd like to give you a brief introduction to the use of spring Interceptor Interceptor Mechanism 、jwt authentication 、redis Distributed cache implementation sso Single sign on , Gossip , Record the steps and share them with you :
- introduce jwt Correlation jar package , In the project pom.xml Introduction in :
1. <dependency>
2. <groupId>com.auth0</groupId>
3. <artifactId>java-jwt</artifactId>
4. <version>2.2.0</version>
5. </dependency>
- Interceptor configuration :
1. <mvc:interceptor>
2. <mvc:mapping path="${adminPath}/**" />
3. <mvc:exclude-mapping path="${adminPath}/rest/login"/>
4. <bean class="com.ml.honghu.interceptor.LoginInterceptor" />
5. </mvc:interceptor>
I have simply configured the intercepted url And filtered url( This depends on your project )
- To write jwt Encryption or decryption tool class of :
1. public class JWT {
2. private static final String SECRET = "HONGHUJWT1234567890QWERTYUIOPASDFGHJKLZXCVBNM";
4. private static final String EXP = "exp";
6. private static final String PAYLOAD = "payload";
8. // encryption
9. public static <T> String sign(T object, long maxAge) {
10. try {
11. final JWTSigner signer = new JWTSigner(SECRET);
12. final Map<String, Object> claims = new HashMap<String, Object>();
13. ObjectMapper mapper = new ObjectMapper();
14. String jsonString = mapper.writeValueAsString(object);
15. claims.put(PAYLOAD, jsonString);
16. claims.put(EXP, System.currentTimeMillis() + maxAge);
17. return signer.sign(claims);
18. } catch(Exception e) {
19. return null;
20. }
21. }
23. // Decrypt
24. public static<T> T unsign(String jwt, Class<T> classT) {
25. final JWTVerifier verifier = new JWTVerifier(SECRET);
26. try {
27. final Map<String,Object> claims= verifier.verify(jwt);
28. if (claims.containsKey(EXP) && claims.containsKey(PAYLOAD)) {
29. String json = (String)claims.get(PAYLOAD);
30. ObjectMapper objectMapper = new ObjectMapper();
31. return objectMapper.readValue(json, classT);
33. }
34. return null;
35. } catch (Exception e) {
36. return null;
37. }
38. }
39. }
This encryption tool class is from the Internet to find , If you want to change , You can modify it according to your own business .
- establish Login.java object , Used for jwt Encryption or decryption of :
1. public class Login implements Serializable{
2. /**
3. *
4. */
5. private static final long serialVersionUID = 1899232511233819216L;
7. /**
8. * user id
9. */
10. private String uid;
12. /**
13. * Login username
14. */
15. private String loginName;
17. /**
18. * The login password
19. */
20. private String password;
22. public Login(){
23. super();
24. }
26. public Login(String uid, String loginName, String password){
27. this.uid = uid;
28. this.loginName = loginName;
29. this.password = password;
30. }
32. public String getUid() {
33. return uid;
34. }
35. public void setUid(String uid) {
36. this.uid = uid;
37. }
38. public String getLoginName() {
39. return loginName;
40. }
41. public void setLoginName(String loginName) {
42. this.loginName = loginName;
43. }
44. public String getPassword() {
45. return password;
46. }
47. public void setPassword(String password) {
48. this.password = password;
49. }
52. }
- Definition RedisLogin object , To pass through uid Go to redis Conduct user Object storage :
1. public class RedisLogin implements Serializable{
2. /**
3. *
4. */
5. private static final long serialVersionUID = 8116817810829835862L;
7. /**
8. * user id
9. */
10. private String uid;
12. /**
13. * jwt Generated token Information
14. */
15. private String token;
17. /**
18. * Time to log in or refresh the app
19. */
20. private long refTime;
22. public RedisLogin(){
24. }
26. public RedisLogin(String uid, String token, long refTime){
27. this.uid = uid;
28. this.token = token;
29. this.refTime = refTime;
30. }
32. public String getUid() {
33. return uid;
34. }
35. public void setUid(String uid) {
36. this.uid = uid;
37. }
38. public String getToken() {
39. return token;
40. }
41. public void setToken(String token) {
42. this.token = token;
43. }
44. public long getRefTime() {
45. return refTime;
46. }
47. public void setRefTime(long refTime) {
48. this.refTime = refTime;
49. }
53. }
- To write LoginInterceptor.java Interceptor
1. public class LoginInterceptor implements HandlerInterceptor{
3. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
4. throws Exception {
5. PrintWriter writer = null;
6. HandlerMethod method = null;
7. try {
8. method = (HandlerMethod) handler;
9. } catch (Exception e) {
10. writer = response.getWriter();
11. ResponseVO responseVO = ResponseCode.buildEnumResponseVO(ResponseCode.REQUEST_URL_NOT_SERVICE, false);
12. responseMessage(response, writer, responseVO);
13. return false;
14. }
15. IsLogin isLogin = method.getMethodAnnotation(IsLogin.class);
16. if(null == isLogin){
17. return true;
18. }
21. response.setCharacterEncoding("utf-8");
22. String token = request.getHeader("token");
23. String uid = request.getHeader("uid");
24. //token non-existent
25. if(StringUtils.isEmpty(token)) {
26. writer = response.getWriter();
27. ResponseVO responseVO = LoginResponseCode.buildEnumResponseVO(LoginResponseCode.LOGIN_TOKEN_NOT_NULL, false);
28. responseMessage(response, writer, responseVO);
29. return false;
30. }
31. if(StringUtils.isEmpty(uid)){
32. writer = response.getWriter();
33. ResponseVO responseVO = LoginResponseCode.buildEnumResponseVO(LoginResponseCode.USERID_NOT_NULL, false);
34. responseMessage(response, writer, responseVO);
35. return false;
36. }
38. Login login = JWT.unsign(token, Login.class);
39. // Decrypt token After loginId From users loginId Judge whether it is consistent
40. if(null == login || !StringUtils.equals(login.getUid(), uid)){
41. writer = response.getWriter();
42. ResponseVO responseVO = LoginResponseCode.buildEnumResponseVO(LoginResponseCode.USERID_NOT_UNAUTHORIZED, false);
43. responseMessage(response, writer, responseVO);
44. return false;
45. }
47. // Verify login time
48. RedisLogin redisLogin = (RedisLogin)JedisUtils.getObject(uid);
49. if(null == redisLogin){
50. writer = response.getWriter();
51. ResponseVO responseVO = LoginResponseCode.buildEnumResponseVO(LoginResponseCode.RESPONSE_CODE_UNLOGIN_ERROR, false);
52. responseMessage(response, writer, responseVO);
53. return false;
54. }
56. if(!StringUtils.equals(token, redisLogin.getToken())){
57. writer = response.getWriter();
58. ResponseVO responseVO = LoginResponseCode.buildEnumResponseVO(LoginResponseCode.USERID_NOT_UNAUTHORIZED, false);
59. responseMessage(response, writer, responseVO);
60. return false;
61. }
62. // system time > The period of validity ( It is beyond the validity period )
63. if (System.currentTimeMillis() > redisLogin.getRefTime()) {
64. writer = response.getWriter();
65. ResponseVO responseVO = LoginResponseCode.buildEnumResponseVO(LoginResponseCode.LOGIN_TIME_EXP, false);
66. responseMessage(response, writer, responseVO);
67. return false;
68. }
70. // Refresh expiration date again
71. redisLogin = new RedisLogin(uid, token, System.currentTimeMillis() + 60L* 1000L* 30L);
72. JedisUtils.setObject(uid , redisLogin, 360000000);
73. return true;
74. }
76. public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
77. ModelAndView modelAndView) throws Exception {
79. }
81. public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
82. throws Exception {
84. }
86. private void responseMessage(HttpServletResponse response, PrintWriter out, ResponseVO responseVO) {
87. response.setContentType("application/json; charset=utf-8");
88. JSONObject result = new JSONObject();
89. result.put("result", responseVO);
90. out.print(result);
91. out.flush();
92. out.close();
93. }
95. }
- Define the exception LoginResponseCode
1. public enum LoginResponseCode {
2. USERID_NOT_NULL(3001," user id Can't be empty ."),
3. LOGIN_TOKEN_NOT_NULL(3002," Sign in token Can't be empty ."),
4. USERID_NOT_UNAUTHORIZED(3003, " user token or ID Verification failed "),
5. RESPONSE_CODE_UNLOGIN_ERROR(421, " Not logged in exception "),
6. LOGIN_TIME_EXP(3004, " Login time is too long , Please login again ");
8. // Member variables
9. private int code; // Status code
10. private String message; // Return message
12. // Construction method
13. private LoginResponseCode(int code,String message) {
14. this.code = code;
15. this.message = message;
16. }
17. public int getCode() {
18. return code;
19. }
20. public void setCode(int code) {
21. this.code = code;
22. }
23. public String getMessage() {
24. return message;
25. }
26. public void setMessage(String message) {
27. this.message = message;
28. }
30. public static ResponseVO buildEnumResponseVO(LoginResponseCode responseCode, Object data) {
31. return new ResponseVO(responseCode.getCode(),responseCode.getMessage(),data);
32. }
34. public static Map<String, Object> buildReturnMap(LoginResponseCode responseCode, Object data) {
35. Map<String, Object> map = new HashMap<String, Object>();
36. map.put("code", responseCode.getCode());
37. map.put("message", responseCode.getMessage());
38. map.put("data", data);
39. return map;
40. }
41. }
- Write unified sso Single sign on Interface :
1. @RequestMapping(value = "/login", method = RequestMethod.POST)
2. public Map<String, Object> login(@RequestBody JSONObject json){
3. String loginName = json.optString("loginName");
4. String password = json.optString("password");
5. // The verification user name cannot be empty
6. if(StringUtils.isEmpty(loginName)){
7. return MemberResponseCode.buildReturnMap(MemberResponseCode.RESPONSE_CODE_USER_NAME_IS_NOT_EMPTY, null);
8. }
9. // Verify user password cannot be empty
10. if(StringUtils.isEmpty(password)){
11. return MemberResponseCode.buildReturnMap(MemberResponseCode.RESPONSE_CODE_PWD_CAN_NOT_BE_EMPTY, null);
12. }
13. // Query database user information according to user name
14. User user = systemService.getBaseUserByLoginName(loginName);
15. // Username or password incorrect
16. if(null == user){
17. return MemberResponseCode.buildReturnMap(MemberResponseCode.RESPONSE_CODE_USER_VALIDATE_NO_SUCCESS, false);
18. }
19. boolean isValidate = systemService.validatePassword(password, user.getPassword());
20. if(!isValidate){
21. return MemberResponseCode.buildReturnMap(MemberResponseCode.RESPONSE_CODE_USER_VALIDATE_NO_SUCCESS, false);
22. }
23. if(isValidate){
24. //HttpSession session =request.getSession(false);
25. Login login = new Login(user.getId(), user.getLoginName(), user.getPassword());
26. // To the user jwt Encryption generation token
27. String token = JWT.sign(login, 60L* 1000L* 30L);
28. Map<String,Object> result =new HashMap<String,Object>();
29. result.put("loginToken", token);
30. result.put("userId", user.getId());
31. result.put("user", user);
33. // Save user information to session
34. //session.setAttribute(user.getId() + "@@" + token, user);
35. // Rebuild user information
36. this.rebuildLoginUser(user.getId(), token);
37. return ResponseCode.buildReturnMap(ResponseCode.RESPONSE_CODE_LOGIN_SUCCESS, result);
38. }
40. return ResponseCode.buildReturnMap(ResponseCode.USER_LOGIN_PWD_ERROR, false);
41. }
- test sso Single sign on :
Return result set :
1. {
2. "message": " User login successful ",
3. "data": {
4. "loginToken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1MDkzODA1OTU0NTksInBheWxvYWQiOiJ7XCJ1aWRcIjpcIjExXCIsXCJsb2dpbk5hbWVcIjpcImFkbWluXCIsXCJwYXNzd29yZFwiOlwiZjU0NGQxM2QyY2EwNDU5ZGQ0ZTU1NzVjNmZkYWIzMzM0MzE1MWFlZjgwYmE5ZTNiN2U1ZjM2MzJcIn0ifQ.56L60WtxHXSu9vNs6XsWy5zbmc3kP_IWG1YpReK50DM",
5. "userId": "11",
6. "user": {
7. "QQ":"2147775633",
8. "id": "11",
9. "isNewRecord": false,
10. "remarks": "",
11. "createDate": "2017-08-08 08:08:08",
12. "updateDate": "2017-10-29 11:23:50",
13. "loginName": "admin",
14. "no": "00012",
15. "name": "admin",
16. "email": "[email protected]",
17. "phone": "400000000",
18. "mobile": "13888888888",
19. "userType": "",
20. "loginIp": "0:0:0:0:0:0:0:1",
21. "loginDate": "2017-10-30 10:48:06",
22. "loginFlag": "1",
23. "photo": "",
24. "idCard": "420888888888888888",
25. "oldLoginIp": "0:0:0:0:0:0:0:1",
26. "oldLoginDate": "2017-10-30 10:48:06",
27. "roleNames": "",
28. "admin": false
29. }
30. },
31. "code": 200
32. }
It's over !!
use java There are too few e-commerce platforms to implement , Use spring cloud technology-built b2b2c There are fewer e-commerce platforms , Distributed Internet e-commerce platform for large enterprises , Introduction PC+ WeChat +APP+ Cloud service cloud business platform system , These include B2B、B2C、C2C、O2O、 The new retail 、 Live e-commerce and other sub platforms .( Enterprise architecture source code can be added ball : Thirty five three six two four seven two fifty nine )