整合JWT
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.4.0</version>
</dependency>
JWT工具类添加
public class JwtUtil {
//过期时间 30min
private static final int EXPIRE_TIME = 30;
//私钥
private static final String TOKEN_SECRET = "privateKey";
private static final String USER_NAME = "name";
/**
* 签发对象:这个用户的id
* 签发时间:现在
* 有效时间:30分钟
* 载荷内容:暂时设计为:这个人的名字
* 加密密钥:这个人的id加上一串字符串
* @param userId
* @param userName
* @return
*/
public static String createToken(Long userId, String userName) {
Calendar nowTime = Calendar.getInstance();
nowTime.add(Calendar.MINUTE,EXPIRE_TIME);
Date expiresDate = nowTime.getTime();
return JWT.create().withAudience(userId+"") //签发对象
.withIssuedAt(new Date()) //发行时间
.withExpiresAt(expiresDate) //有效时间
.withClaim(USER_NAME, userName) //载荷,随便写几个都可以
.sign(Algorithm.HMAC256(userId+TOKEN_SECRET)); //加密
}
/**
* 检验合法性,其中secret参数就应该传入的是用户的id
* @param token
* @throws TokenUnavailableException
*/
public static void verifyToken(String token, String secret) throws TokenUnavailableException {
try {
JWTVerifier verifier = JWT.require(Algorithm.HMAC256(secret+TOKEN_SECRET)).build();
verifier.verify(token);
} catch (Exception e) {
//效验失败
//自定义的一个异常
throw new TokenUnavailableException();
}
}
/**
* 获取签发对象
*/
public static String getAudience(String token) throws TokenUnavailableException {
String audience = null;
try {
audience = JWT.decode(token).getAudience().get(0);
} catch (JWTDecodeException j) {
//这里是token解析失败
throw new TokenUnavailableException();
}
return audience;
}
}
token验证拦截器添加
@Slf4j
public class AuthenticationInterceptor implements HandlerInterceptor {
@Autowired
private TestService testService;
//Controller逻辑执行之前
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object object) throws Exception {
// 从请求头中取出 token 这里需要和前端约定好把jwt放到请求头一个叫token的地方
String token = request.getHeader("token");
// 如果不是映射到controller方法直接通过
// ResourceHttpRequestHandler 是静态资源,无需拦截
// HandlerMethod 是Controller中的方法
if (!(object instanceof HandlerMethod)) {
return true;
}
HandlerMethod handlerMethod = (HandlerMethod) object;
Method method = handlerMethod.getMethod();
//检查是否有NoNeedToken注释,有则跳过认证
if (method.isAnnotationPresent(NoNeedToken.class)) {
return true;
}
//默认全部检查
else {
// 执行认证
if (token == null) {
//这里其实是登录失效,没token了
throw new NeedToLoginException();
}
// 获取 token 中的 userId
String userId = JwtUtil.getAudience(token);
Test user = testService.getById(userId);
if (user == null) {
//这个错误也是我自定义的
throw new UserNotExistException();
}
// 验证 token
JwtUtil.verifyToken(token, userId);
return true;
}
}
//Controller逻辑执行完毕但是视图解析器还未进行解析之前
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
log.info("postHandle....");
}
//Controller逻辑和视图解析器执行完毕
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
log.info("afterCompletion....");
}
}
注册和配置拦截器 & 添加跨域配置
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
//默认拦截所有路径
registry.addInterceptor(authenticationInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**");;
}
// 注册bean到spring
@Bean
public AuthenticationInterceptor authenticationInterceptor() {
return new AuthenticationInterceptor();
}
/**
* 跨域配置
* 前后端分离必须配置,出现跨域之后前端无法访问后端接口
* @param registry
*/
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**");
}
}