SpringBoot:前后端分离Token校验(Redis鉴权成功自动延长期限)

SpringBoot:前后端分离Token校验(Redis鉴权成功自动延长期限)

pom.xml引入jedis

1
2
3
4
5
6
<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>

token鉴权拦截器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
package com.fufu.interceptor;

import com.alibaba.fastjson.JSONObject;
import com.fufu.annotation.AuthToken;
import com.fufu.constant.SysConstant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import redis.clients.jedis.Jedis;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.lang.reflect.Method;

/**
* token鉴权拦截器
*/
@Component
public class AuthorizationInterceptor implements HandlerInterceptor {
private final static Logger log = LoggerFactory.getLogger(AuthorizationInterceptor.class);
//存放鉴权信息的Header名称,默认是Authorization
private String httpHeaderName = "token";
//鉴权失败后返回的错误信息,默认为401 unauthorized
private String unauthorizedErrorMessage = "401 unauthorized";
//鉴权失败后返回的HTTP错误码,默认为401
private int unauthorizedErrorCode = HttpServletResponse.SC_UNAUTHORIZED;
/**
* 存放登录用户模型Key的Request Key
*/
public static final String REQUEST_CURRENT_KEY = "REQUEST_CURRENT_KEY";

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (!(handler instanceof HandlerMethod)) {
return true;
}
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
// 如果打上了AuthToken注解则需要验证token
if (method.getAnnotation(AuthToken.class) != null || handlerMethod.getBeanType().getAnnotation(AuthToken.class) != null) {
String token = request.getHeader(httpHeaderName);
log.info("token is {}", token);
String username = "";
Jedis jedis = new Jedis("localhost", 6379);
if (token != null && token.length() != 0) {
username = jedis.get(token);
log.info("username is {}", username);
}
if (username != null && !username.trim().equals("")) {
//log.info("token birth time is: {}",jedis.get(username+token));
Long tokeBirthTime = Long.valueOf(jedis.get(token + username));
log.info("token Birth time is: {}", tokeBirthTime);
Long diff = System.currentTimeMillis() - tokeBirthTime;
log.info("token is exist : {} ms", diff);
if (diff > SysConstant.TOKEN_RESET_TIME) {
jedis.expire(username, SysConstant.TOKEN_EXPIRE_TIME);
jedis.expire(token, SysConstant.TOKEN_EXPIRE_TIME);
log.info("Reset expire time success!");
Long newBirthTime = System.currentTimeMillis();
jedis.set(token + username, newBirthTime.toString());
}
//用完关闭
jedis.close();
request.setAttribute(REQUEST_CURRENT_KEY, username);
return true;
} else {
JSONObject jsonObject = new JSONObject();
PrintWriter out = null;
try {
response.setStatus(unauthorizedErrorCode);
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
jsonObject.put("ret", ((HttpServletResponse) response).getStatus());
jsonObject.put("msg", HttpStatus.UNAUTHORIZED);
out = response.getWriter();
out.println(jsonObject);
return false;
} catch (Exception e) {
e.printStackTrace();
} finally {
if (null != out) {
out.flush();
out.close();
}
}
}
}
request.setAttribute(REQUEST_CURRENT_KEY, null);
return true;
}

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}

拦截器添加

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
package com.fufu.interceptor;

import com.alibaba.fastjson.JSONObject;
import com.fufu.annotation.AuthToken;
import com.fufu.constant.SysConstant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import redis.clients.jedis.Jedis;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.lang.reflect.Method;

/**
* token鉴权拦截器
*/
@Component
public class AuthorizationInterceptor implements HandlerInterceptor {
private final static Logger log = LoggerFactory.getLogger(AuthorizationInterceptor.class);
//存放鉴权信息的Header名称,默认是Authorization
private String httpHeaderName = "token";
//鉴权失败后返回的错误信息,默认为401 unauthorized
private String unauthorizedErrorMessage = "401 unauthorized";
//鉴权失败后返回的HTTP错误码,默认为401
private int unauthorizedErrorCode = HttpServletResponse.SC_UNAUTHORIZED;
/**
* 存放登录用户模型Key的Request Key
*/
public static final String REQUEST_CURRENT_KEY = "REQUEST_CURRENT_KEY";

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (!(handler instanceof HandlerMethod)) {
return true;
}
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
// 如果打上了AuthToken注解则需要验证token
if (method.getAnnotation(AuthToken.class) != null || handlerMethod.getBeanType().getAnnotation(AuthToken.class) != null) {
String token = request.getHeader(httpHeaderName);
log.info("token is {}", token);
String username = "";
Jedis jedis = new Jedis("localhost", 6379);
if (token != null && token.length() != 0) {
username = jedis.get(token);
log.info("username is {}", username);
}
if (username != null && !username.trim().equals("")) {
//log.info("token birth time is: {}",jedis.get(username+token));
Long tokeBirthTime = Long.valueOf(jedis.get(token + username));
log.info("token Birth time is: {}", tokeBirthTime);
Long diff = System.currentTimeMillis() - tokeBirthTime;
log.info("token is exist : {} ms", diff);
if (diff > SysConstant.TOKEN_RESET_TIME) {
jedis.expire(username, SysConstant.TOKEN_EXPIRE_TIME);
jedis.expire(token, SysConstant.TOKEN_EXPIRE_TIME);
log.info("Reset expire time success!");
Long newBirthTime = System.currentTimeMillis();
jedis.set(token + username, newBirthTime.toString());
}
//用完关闭
jedis.close();
request.setAttribute(REQUEST_CURRENT_KEY, username);
return true;
} else {
JSONObject jsonObject = new JSONObject();
PrintWriter out = null;
try {
response.setStatus(unauthorizedErrorCode);
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
jsonObject.put("ret", ((HttpServletResponse) response).getStatus());
jsonObject.put("msg", HttpStatus.UNAUTHORIZED);
out = response.getWriter();
out.println(jsonObject);
return false;
} catch (Exception e) {
e.printStackTrace();
} finally {
if (null != out) {
out.flush();
out.close();
}
}
}
}
request.setAttribute(REQUEST_CURRENT_KEY, null);
return true;
}

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}

系统参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.fufu.constant;

public final class SysConstant {

/**
* 设置删除标志为真
*/
public static final Integer DEL_FLAG_TRUE = 1;

/**
* 设置删除标志为假
*/
public static final Integer DEL_FLAG_FALSE = 0;

/**
* redis存储token设置的过期时间
*/
public static final Integer TOKEN_EXPIRE_TIME = 60 * 2;

/**
* 设置可以重置token过期时间的时间界限
*/
public static final Integer TOKEN_RESET_TIME = 1000 * 100;


}

MD5生成token

1
2
3
4
5
6
7
8
9
10
package com.fufu.tools;

import org.springframework.stereotype.Component;

@Component
public interface TokenGenerator {

public String generate(String... strings);

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.fufu.tools;

import org.springframework.stereotype.Component;
import org.springframework.util.DigestUtils;

@Component
public class Md5TokenGenerator implements TokenGenerator {

@Override
public String generate(String... strings) {
long timestamp = System.currentTimeMillis();
String tokenMeta = "";
for (String s : strings) {
tokenMeta = tokenMeta + s;
}
tokenMeta = tokenMeta + timestamp;
String token = DigestUtils.md5DigestAsHex(tokenMeta.getBytes());
return token;
}
}

Controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@ApiOperation(value="token鉴权", notes="token鉴权")
@GetMapping(value="loginToken")
@ResponseBody
public String login(String username, String password, HttpServletResponse response) {
User user = loginService.findByUsername(username);
if (user != null && user.getPassword().equals(password)) {
Jedis jedis = new Jedis("localhost", 6379);
String token = tokenGenerator.generate(username, password);
jedis.set(username, token);
jedis.expire(username, SysConstant.TOKEN_EXPIRE_TIME);
jedis.set(token, username);
jedis.expire(token, SysConstant.TOKEN_EXPIRE_TIME);
Long currentTime = System.currentTimeMillis();
jedis.set(token + username, currentTime.toString());
//用完关闭
jedis.close();
return JsonUtil.getInstance().putData("ret", 1).putData("token", token).pushData();
} else {
return JsonUtil.getInstance().putData("ret", -1).putData("msg", "token校验失败").pushData();
}
}

效果图

"图片描述"

"图片描述"

源码:https://github.com/qq1028951741/springbootdemo or 右上角github进去,springbootdemo项目,如果对您有帮助,麻烦点下star,谢谢


人生两苦:想要却不得,拥有却失去。 –褚禄山
珍惜当下,与君共勉~


本文标题:SpringBoot:前后端分离Token校验(Redis鉴权成功自动延长期限)

文章作者:fufua

发布时间:2018年12月06日 - 10:43:13

最后更新:2018年12月06日 - 10:30:33

原始链接:https://qq1028951741.github.io/2018/12/06/SpringBoot:前后端分离Token校验(Redis鉴权成功自动延长期限)/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

this is end, thank you for reading