SpringBoot集成JWT实现token验证
本文抄袭自 https://www.jianshu.com/p/e88d3f8151db
本文在 使用IDEA快速搭建基于Maven的SpringBoot项目(集成使用Redis) 基础上继续
引入JWT依赖
<dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.4.0</version> </dependency>
自定义两个注解
@Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface UserLoginToken { boolean required() default true; }
@Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface PassToken { boolean required() default true; }
登录用户类
public class LoginUser implements Serializable { String id; String username; String password; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
拦截器
package com.blaze.demo.interceptor; import com.auth0.jwt.JWT; import com.auth0.jwt.JWTVerifier; import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.exceptions.JWTDecodeException; import com.auth0.jwt.exceptions.JWTVerificationException; import com.blaze.demo.annotation.PassToken; import com.blaze.demo.annotation.UserLoginToken; import com.blaze.demo.model.LoginUser; import com.blaze.demo.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.lang.reflect.Method; public class AuthenticationInterceptor implements HandlerInterceptor { @Autowired UserService userService; @Override public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception { String token = httpServletRequest.getHeader("token");// 从 http 请求头中取出 token // 如果不是映射到方法直接通过 if(!(object instanceof HandlerMethod)){ return true; } HandlerMethod handlerMethod=(HandlerMethod)object; Method method=handlerMethod.getMethod(); //检查是否有passtoken注释,有则跳过认证 if (method.isAnnotationPresent(PassToken.class)) { PassToken passToken = method.getAnnotation(PassToken.class); if (passToken.required()) { return true; } } //检查有没有需要用户权限的注解 if (method.isAnnotationPresent(UserLoginToken.class)) { UserLoginToken userLoginToken = method.getAnnotation(UserLoginToken.class); if (userLoginToken.required()) { // 执行认证 if (token == null) { throw new RuntimeException("无token,请重新登录"); } // 获取 token 中的 user id String userId; try { userId = JWT.decode(token).getAudience().get(0); } catch (JWTDecodeException j) { throw new RuntimeException("401"); } LoginUser user = userService.findUserById(userId); if (user == null) { throw new RuntimeException("用户不存在,请重新登录"); } // 验证 token JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getPassword())).build(); try { jwtVerifier.verify(token); } catch (JWTVerificationException e) { throw new RuntimeException("401"); } return true; } } return true; } @Override public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception { } }
配置拦截器
package com.blaze.demo.config; import com.blaze.demo.interceptor.AuthenticationInterceptor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; @Configuration public class InterceptorConfig extends WebMvcConfigurerAdapter { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(authenticationInterceptor()) .addPathPatterns("/**"); // 拦截所有请求,通过判断是否有 @LoginRequired 注解 决定是否需要登录 } @Bean public AuthenticationInterceptor authenticationInterceptor() { return new AuthenticationInterceptor(); } }
接口Controller
@GetMapping("/test01") public String test01() { return "不需要token"; } @UserLoginToken @GetMapping("/test02") public String test02() { return "需要token"; } @ResponseBody @PostMapping("/login") public Object login(@ApiParam(value = "账号") @RequestParam String account, @ApiParam(value = "密码") @RequestParam String password) { JSONObject jsonObject = new JSONObject(); LoginUser userForBase = userService.queryAdminByAccount(account); if (userForBase == null) { jsonObject.put("message", "登录失败,用户不存在"); return jsonObject; } else { if (!userForBase.getPassword().equals(password)) { jsonObject.put("message", "登录失败,密码错误"); return jsonObject; } else { String token = getToken(userForBase); jsonObject.put("token", token); jsonObject.put("user", userForBase); return jsonObject; } } } public static String getToken(LoginUser user) { String token = ""; token = JWT.create().withAudience(user.getId()) .sign(Algorithm.HMAC256(user.getPassword())); return token; }