修改框架登录认证逻辑
This commit is contained in:
@@ -3,7 +3,6 @@ package org.jiayunet.interceptor;
|
||||
import java.io.IOException;
|
||||
import java.time.Instant;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@@ -37,6 +36,7 @@ import org.jiayunet.tool.server.RedisServerTool;
|
||||
|
||||
/**
|
||||
* jwt过滤器
|
||||
* <p>所有请求先尝试解析token设置认证信息,再根据接口是否公开决定放行或拦截</p>
|
||||
*
|
||||
* @author zk
|
||||
*/
|
||||
@@ -44,26 +44,19 @@ import org.jiayunet.tool.server.RedisServerTool;
|
||||
@Slf4j
|
||||
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
|
||||
|
||||
/**
|
||||
* 加密密钥
|
||||
*/
|
||||
/** 加密密钥 */
|
||||
@Value("${app.secret.token:youweiqingnian123}")
|
||||
private String secret;
|
||||
|
||||
/**
|
||||
* token过期时间
|
||||
*/
|
||||
/** token过期时间(秒) */
|
||||
@Value("${app.login.token.exceed_time:43200}")
|
||||
private int tokenExceedTime;
|
||||
/**
|
||||
* 忽略请求路径
|
||||
*/
|
||||
|
||||
/** 忽略请求路径 */
|
||||
@Value("${app.ignore.urls}")
|
||||
private String ignoreUrls;
|
||||
|
||||
/**
|
||||
* 全局配置路径
|
||||
*/
|
||||
/** 全局配置路径 */
|
||||
@Value("${server.servlet.context-path}")
|
||||
private String contextPath;
|
||||
|
||||
@@ -72,77 +65,83 @@ public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
|
||||
// 1. 无条件尝试解析token
|
||||
boolean authenticated = tryAuthenticate(request);
|
||||
|
||||
// 忽略接口放行
|
||||
// 2. 公开接口直接放行,不管token状态
|
||||
if (ifCurrentUrl(ignoreUrls, request.getRequestURI())) {
|
||||
filterChain.doFilter(request, response);
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取token:优先从cookie获取,不存在则从请求头获取
|
||||
String token = null;
|
||||
if (request.getCookies() != null) {
|
||||
for (Cookie cookie : request.getCookies()) {
|
||||
if ("Token".equals(cookie.getName())) {
|
||||
token = cookie.getValue();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!StringUtils.hasText(token)) {
|
||||
token = request.getHeader("Token");
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (!StringUtils.hasText(token)) {
|
||||
// 放行
|
||||
// 3. 非公开接口,认证失败则拦截
|
||||
Assert.isTrue(authenticated, "用户未登录或登录过期");
|
||||
filterChain.doFilter(request, response);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* 尝试解析token并设置认证信息
|
||||
* <p>1. 提取token 2. JWT解码 3. Redis校验 4. 设备有效性过滤 5. 续期 6. 设置SecurityContext和MDC</p>
|
||||
*
|
||||
* @return true=认证成功 false=认证失败
|
||||
*/
|
||||
private boolean tryAuthenticate(HttpServletRequest request) {
|
||||
String token = resolveToken(request);
|
||||
if (!StringUtils.hasText(token)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 验证token
|
||||
try {
|
||||
Algorithm algorithm = Algorithm.HMAC256(secret);
|
||||
DecodedJWT decodedJwt = JWT.require(algorithm).build().verify(token);
|
||||
Long userId = decodedJwt.getClaim("userId").asLong();
|
||||
String uuId = decodedJwt.getClaim("uuId").asString();
|
||||
|
||||
// 获取redis信息
|
||||
// Redis校验
|
||||
String redisKey = PreRedisKeyName.LOGIN_TOKEN + userId;
|
||||
RedisLoginTokenInfo info = null;
|
||||
info = redisServerTool.get(redisKey, RedisLoginTokenInfo.class);
|
||||
Assert.notNull(info, "用户未登录");
|
||||
|
||||
|
||||
// 判断登录有效
|
||||
|
||||
// 获取登录设备信息
|
||||
List<RedisLoginTokenInfo.LoginDevice> devices = info.getLoginDevices();
|
||||
|
||||
// 过滤过期
|
||||
devices = devices.stream().filter(v -> v.getLastLoginTime().isBefore(new Date(System.currentTimeMillis() + tokenExceedTime * 1000L).toInstant())).collect(Collectors.toList());
|
||||
RedisLoginTokenInfo info = redisServerTool.get(redisKey, RedisLoginTokenInfo.class);
|
||||
if (info == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 过滤过期设备
|
||||
List<RedisLoginTokenInfo.LoginDevice> devices = info.getLoginDevices().stream().filter(v -> v.getLastLoginTime().plusSeconds(tokenExceedTime).isAfter(Instant.now())).collect(Collectors.toList());
|
||||
Map<String, RedisLoginTokenInfo.LoginDevice> map = devices.stream().collect(Collectors.toMap(RedisLoginTokenInfo.LoginDevice::getUuId, v -> v));
|
||||
Assert.isTrue(map.containsKey(uuId), "登录过期");
|
||||
if (!map.containsKey(uuId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 续期时间
|
||||
// 续期
|
||||
map.get(uuId).setLastLoginTime(Instant.now());
|
||||
info.setLoginDevices(devices);
|
||||
redisServerTool.set(redisKey, info, tokenExceedTime, TimeUnit.SECONDS);
|
||||
|
||||
// 登录
|
||||
UsernamePasswordAuthenticationToken authenticationToken =
|
||||
new UsernamePasswordAuthenticationToken(info.getUserId(), info,
|
||||
info.getAuthority().stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList()));
|
||||
// 设置SecurityContext
|
||||
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(info.getUserId(), info, info.getAuthority().stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList()));
|
||||
authenticationToken.setDetails(info);
|
||||
|
||||
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
|
||||
|
||||
MDC.put("userId", userId.toString());
|
||||
return true;
|
||||
|
||||
filterChain.doFilter(request, response);
|
||||
} catch (Exception e) {
|
||||
log.debug("Token解析失败: {}", e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从请求中提取token,优先cookie,其次请求头
|
||||
*/
|
||||
private String resolveToken(HttpServletRequest request) {
|
||||
if (request.getCookies() != null) {
|
||||
for (Cookie cookie : request.getCookies()) {
|
||||
if ("Token".equals(cookie.getName())) {
|
||||
return cookie.getValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
return request.getHeader("Token");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -157,18 +156,13 @@ public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
|
||||
if (!StringUtils.hasText(ignoreUrls)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 处理本次请求路径 剔除全局路径
|
||||
if (!StringUtils.hasText(currentUrl)) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.hasText(contextPath)) {
|
||||
currentUrl = currentUrl.replaceFirst(contextPath, "").replaceAll(charToRemove, "");
|
||||
}
|
||||
|
||||
// 处理需要被忽略的字段
|
||||
List<String> urls = Arrays.stream(ignoreUrls.split(",")).map(item -> item.replaceAll(charToRemove, "")).filter(item -> !item.isEmpty()).distinct().collect(Collectors.toList());
|
||||
|
||||
for (String str : urls) {
|
||||
if (currentUrl.startsWith(str)) {
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user