package com.monkeylessey.framework.security.filter;
|
|
|
import com.auth0.jwt.exceptions.JWTVerificationException;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.monkeylessey.constant.HttpStatusConstants;
|
import com.monkeylessey.constant.RedisKeyPrefixConstants;
|
import com.monkeylessey.sys.domain.vo.SysUserVO;
|
import com.monkeylessey.framework.service.XpUserDetailsService;
|
import com.monkeylessey.response.ResponseData;
|
import com.monkeylessey.framework.utils.RedisUtil;
|
import com.monkeylessey.framework.utils.TokenUtil;
|
import org.apache.commons.lang3.StringUtils;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.http.MediaType;
|
import org.springframework.security.authentication.AuthenticationManager;
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
|
|
import javax.servlet.FilterChain;
|
import javax.servlet.ServletException;
|
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletResponse;
|
import java.io.IOException;
|
import java.util.Date;
|
import java.util.concurrent.TimeUnit;
|
|
/**
|
* @author 29443
|
* @date 2022/4/4
|
*/
|
public class JwtTokenFilter extends BasicAuthenticationFilter {
|
|
@Autowired
|
private TokenUtil tokenUtil;
|
|
@Autowired
|
private RedisUtil redisUtil;
|
|
@Autowired
|
private XpUserDetailsService userDetailsService;
|
|
public JwtTokenFilter(AuthenticationManager authenticationManager) {
|
super(authenticationManager);
|
}
|
|
@Override
|
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
|
|
// 获取请求头的token
|
String token = request.getHeader(tokenUtil.getHeader());
|
// token为空,有可能是访问放行或可匿名的资源,让它继续走
|
if (StringUtils.isEmpty(token)) {
|
chain.doFilter(request, response);
|
return;
|
}
|
try {
|
// 验证token合法性,并取出值
|
tokenUtil.verifyToken(token);
|
SysUserVO user = tokenUtil.getCurrentUserInfo(token);
|
|
String key = RedisKeyPrefixConstants.TOKEN_PREFIX + user.getId();
|
if (!redisUtil.hasKey(key)) {
|
createResponse(response);
|
return;
|
} else if (token.equals(redisUtil.getValue(key, String.class))) {
|
// 这里需要往SecurityContextHolder放入凭证信息,代表已经认证的用户
|
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(tokenUtil.getCurrentUserInfo(token), null, userDetailsService.getUserPermissions(user.getUserName()));
|
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
|
chain.doFilter(request, response);
|
// 检查是否需要刷新redis token过期时间(距离过期不到一小时)
|
Date date = new Date();
|
if ((redisUtil.getExpire(key) - date.getTime()) / 3600 < 1) {
|
redisUtil.saveForValueWithExpire(key, token, (long) tokenUtil.getExpire(), TimeUnit.MINUTES);
|
}
|
} else {
|
createResponse(response);
|
}
|
// 只捕获token验证异常
|
} catch (JWTVerificationException e) {
|
// token 无效
|
ResponseData error = ResponseData.error("Invalid Token", HttpStatusConstants.UNAUTHORIZED);
|
String s = new ObjectMapper().writeValueAsString(error);
|
response.setCharacterEncoding("utf-8");
|
response.getWriter().print(s);
|
response.setStatus(org.springframework.http.HttpStatus.UNAUTHORIZED.value());
|
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
|
}
|
}
|
|
/**
|
* 创建token过期的响应
|
*
|
* @param response
|
* @throws IOException
|
*/
|
private void createResponse(HttpServletResponse response) throws IOException {
|
// token 失效,请重新登录
|
ResponseData error = ResponseData.error("身份过期,请重新登录", HttpStatusConstants.UNAUTHORIZED);
|
String s = new ObjectMapper().writeValueAsString(error);
|
response.setCharacterEncoding("utf-8");
|
response.getWriter().print(s);
|
response.setStatus(org.springframework.http.HttpStatus.UNAUTHORIZED.value());
|
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
|
}
|
}
|