使用 jwt生产令牌(token),鉴权。
/**
* @Author: lijia
* @Description: 权限验证过滤器
* @CreateDate: 2021/5/21 11:56
*/
//标识filter
@WebFilter(filterName = "AuthenticationFilter", urlPatterns = {"/adminService/*", "/otherService/*"})
public class AuthenticationFilter implements Filter {
@Autowired
private RedisTemplate<Object, Object> redisTemplate;
//忽略请求地址
public List<String> ignoreUrl
= Arrays.asList(
"/adminService/auth/token",
"/adminService/auth/refreshToken");
@Override
public void init(FilterConfig filterConfig) {
System.out.println("AuthenticationFilter---->init()");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
//获取请求URI
String requestURI = httpRequest.getRequestURI();
if (ignoreUrl.contains(requestURI)) {
//放行
filterChain.doFilter(httpRequest, httpResponse);
} else {
// 从 http 请求头中取出 token
String token = httpRequest.getHeader("token");
//没有token
if (StringUtil.isBlank(token)) {
BaseResponse baseResponse = new BaseResponse();
baseResponse.setMessage("token不能为空!")
.setCode(SystemResponseStatusCode.TOKEN_NONE);
httpServletResponse.setStatus(SystemResponseStatusCode.UNAUTHORIZED);
httpServletResponse.setContentType("application/json; charset=UTF-8");
httpServletResponse.getWriter()
.write(JSONObject.toJSONString(baseResponse));
} else {
// 自定义前缀
String prefix = "WEB";
// 校验token,解析出userId
String userId = verifyJWT(token, prefix);
if (StringUtil.isBlank(userId)) {
BaseResponse baseResponse = new BaseResponse();
baseResponse.setMessage("token错误!")
.setCode(SystemResponseStatusCode.TOKEN_NONE);
httpResponse.setStatus(SystemResponseStatusCode.UNAUTHORIZED);
httpResponse.setContentType("application/json; charset=UTF-8");
httpResponse.getWriter()
.write(JSONObject.toJSONString(baseResponse));
} else {
// 判断token是否过期
String key = MD5Helper.md5(userId);
Object tokenObject = redisTemplate.opsForHash().get(key, "token");
String redisToken=tokenObject==null?"" : String.valueOf(tokenObject);
if (!token.equals(redisToken)) {
BaseResponse baseResponse = new BaseResponse();
baseResponse.setMessage("token失效!")
.setCode(SystemResponseStatusCode.TOKEN_NONE);
httpResponse.setStatus(SystemResponseStatusCode.UNAUTHORIZED);
httpResponse.setContentType("application/json; charset=UTF-8");
httpResponse.getWriter()
.write(JSONObject.toJSONString(baseResponse));
} else {
HeaderMapRequestWrapper requestWrapper = new HeaderMapRequestWrapper(httpServletRequest);
requestWrapper.addHeader("userId", userId);
filterChain.doFilter(requestWrapper, httpServletResponse);
}
}
}
}
}
@Override
public void destroy() {
}
/**
* JWT验证
* @param token prefix
* @return urserId
*/
private String verifyJWT(String token, String prefix) {
String userId;
try {
Algorithm algorithm = Algorithm.HMAC256(prefix);
JWTVerifier verifier = JWT.require(algorithm)
.withIssuer("userId")
.build();
DecodedJWT decodedJWT = verifier.verify(token);
userId = decodedJWT.getClaim("userId").asString();
} catch (JWTVerificationException e) {
e.printStackTrace();
return "";
}
return userId;
}
}
请求头参数包装类
/**
* @Author: lijia
* @Description: 请求头参数包装
* @CreateDate: 2021/5/19 14:40
*/
public class HeaderMapRequestWrapper extends HttpServletRequestWrapper {
/**
* construct a wrapper for this request
*
* @param request
*/
public HeaderMapRequestWrapper(HttpServletRequest request) {
super(request);
}
private Map<String, String> headerMap = new HashMap<>();
/**
* add a header with given name and value
*
* @param name
* @param value
*/
public void addHeader(String name, String value) {
headerMap.put(name, value);
}
@Override
public String getHeader(String name) {
String headerValue = super.getHeader(name);
if (headerMap.containsKey(name)) {
headerValue = headerMap.get(name);
}
return headerValue;
}
/**
* get the Header names
*/
@Override
public Enumeration<String> getHeaderNames() {
List<String> names = Collections.list(super.getHeaderNames());
for (String name : headerMap.keySet()) {
names.add(name);
}
return Collections.enumeration(names);
}
@Override
public Enumeration<String> getHeaders(String name) {
List<String> values = Collections.list(super.getHeaders(name));
if (headerMap.containsKey(name)) {
values = Arrays.asList(headerMap.get(name));
}
return Collections.enumeration(values);
}
}
@WebFilter注解是由Servlet提供的,Springboot默认是不会扫描到该注解。
@MapperScan("com.lijia.dao")
@EnableSwagger2
@SpringBootApplication(scanBasePackages = "com.lijia")
//扫描Servlet的注解
@ServletComponentScan(basePackages = "com.lijia.filter")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@Bean
public FilterRegistrationBean filterRegistration() {
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(authenticationFilter());
registrationBean.addUrlPatterns("/*");
registrationBean.setName("authenticationFilter");
//设置优先级,数越小优先级越高
registrationBean.setOrder(1);
return registrationBean;
}
@Bean
public Filter authenticationFilter() {
return new AuthenticationFilter();
}
当使用springboot提供的注解(@Component 、@Configuration)来标识自定义过滤器时,@WebFilter注解的urlPatterns参数配置会失效,默认变成了 urlPatterns="/*"。
在自定义过滤器使用@Autowired自动装载注入Bean可能为null。解决:使用WebApplicationContextUtils来获取
ServletContext servletContext = servletRequest.getServletContext();
WebApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
Bean bean=webApplicationContext.getBean(Bean.class);