1. Jwt 工具类
引入依赖
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>4.4.0</version>
</dependency>
JwtUtil 类包含了两个静态方法:generateToken() 用于生成 JWT,verifyToken() 用于验证 JWT
public class JwtUtil {
//密钥
private static final String SECRET_KEY = "xxxxxxxxx";
// 过期时间60分钟
private static final long EXPIRE_TIME = 60 * 60 * 1000;
/**
* 生成签名
*
* @param claims
* @return
*/
public static String generateToken(Map<String, Object> claims) {
var jwtBuilder = JWT.create();
// 设置传入的字典中的声明
for (Map.Entry<String, Object> entry : claims.entrySet()) {
jwtBuilder.withClaim(entry.getKey(), entry.getValue().toString());
}
//过期时间
Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
Algorithm algorithm = Algorithm.HMAC256(SECRET_KEY);
return jwtBuilder.withExpiresAt(date).sign(algorithm);
}
/**
* 校验token是否正确
*
* @param token
* @return
*/
public static boolean verifyToken(String token) {
try {
if (token.startsWith("Bearer ")) {
token = token.replace("Bearer ", "");
return false;
}
Algorithm algorithm = Algorithm.HMAC256(SECRET_KEY);
DecodedJWT jwt = JWT.require(algorithm)
.build()
.verify(token);
return true;
} catch (Exception exception) {
return false;
}
}
/**
* 获得token中的用户信息(无需secret解密也能获得)
*
* @param token
* @return
*/
public static String getUsername(String token) {
try {
if (token.startsWith("Bearer ")) {
token = token.replace("Bearer ", "");
}
DecodedJWT jwt = JWT.decode(token);
return jwt.getClaim("userName").asString();
} catch (JWTDecodeException e) {
return null;
}
}
}
2. 匿名访问注解
自定义匿名访问注解,接口添加该注解,则跳过Jwt权限验证。
/**
* 自定义注解
* 允许匿名访问
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AllowAnon {
boolean required() default true;
}
3. Jwt验证拦截器
public class JwtInterceptor implements HandlerInterceptor {
/**
* 在请求处理之前进行调用(Controller方法调用之前)
*
* @param request
* @param response
* @param handler
* @return
* @throws IOException
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
System.out.println("Jwt Interceptor preHandle");
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
//检查有没有允许匿名访问的注解
if (method.isAnnotationPresent(AllowAnon.class)) {
AllowAnon allowAnon = method.getAnnotation(AllowAnon.class);
if (allowAnon.required()) {
//允许匿名访问(无需权限)
return true;
}
}
String authorizationHeader = request.getHeader("Authorization");
if (authorizationHeader == null || !authorizationHeader.startsWith("Bearer ")) {
ResponseErrorMessage(response);
return false;
}
String token = authorizationHeader.substring(7);
try {
//验证token
if (JwtUtil.verifyToken(token)) {
//验证成功
return true;
} else {
//验证失败
ResponseErrorMessage(response);
return false;
}
} catch (Exception e) {
ResponseErrorMessage(response);
return false;
}
}
/**
* 请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)
* preHandle方法处理之后这个方法会被调用,如果控制器Controller出现了异常,则不会执行此方法
*
* @param request
* @param response
* @param handler
* @param modelAndView
* @throws Exception
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("Jwt Interceptor postHandle");
}
/**
* 不管有没有异常,这个afterCompletion都会被调用
*
* @param request
* @param response
* @param handler
* @param ex
* @throws Exception
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("Jwt Interceptor afterCompletion");
}
/**
* 响应错误消息
*
* @param response
* @throws IOException
*/
private void ResponseErrorMessage(HttpServletResponse response) throws IOException {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentType("application/json; charset=UTF-8");
response.getWriter().write("{\"success\":false,\"message\":\"授权失败\",\"data\":null}");
}
}
4. 注册拦截器
//注册拦截器配置
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
/**
* 重写addInterceptors()实现拦截器
* 配置:要拦截的路径以及不拦截的路径
*
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
System.out.println("InterceptorConfig addInterceptors");
registry.addInterceptor(jwtInterceptor()) //配置拦截规则
.addPathPatterns("/api/**") // 拦截所有请求,通过判断token是否合法来决定是否需要登录
.excludePathPatterns(
"/api/user/register" //注册
);//允许匿名访问放行的请求
}
@Bean
public JwtInterceptor jwtInterceptor() {
return new JwtInterceptor();
}
}
5. 控制器
@RestController
@RequestMapping("/api/user")
public class UserController {
/**
* 注册(无需jwt验证,InterceptorConfig定义排除JwtInterceptor验证路由)
*
* @return
*/
@PostMapping("register")
public String register() {
return "注册成功";
}
/**
* 登录(无需jwt验证,添加AllowAnon允许匿名访问注解)
*
* @return
*/
@AllowAnon
@PostMapping("login")
public String login() {
Map<String, Object> claims = new HashMap<>();
claims.put("userId", "9");
claims.put("userName", "usernine");
//生成token
var token = JwtUtil.generateToken(claims);
return token;
}
/**
* 详情(需要验证)
*
* @return
*/
@GetMapping("detail")
public void getUserDetail(@RequestHeader("Authorization") String token) {
//获取当前用户名
var username = JwtUtil.getUsername(token);
}
}