SpringBoot集成JWT实现token验证
SpringBoot集成JWT实现token验证
1、技术概述,描述这个技术是做什么?学习该技术的原因,技术的难点在哪里。
-
什么是JWT
Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON
的开放标准((RFC 7519).定义了一种简洁的,自包含的方法用于通信双方之间以JSON
对象的形式安全的传递信息。因为数字签名的存在,这些信息是可信的,JWT可以使用HMAC
算法或者是RSA
的公私秘钥对进行签名。
-
学习原因
开发后端登录接口,为了安全需要,防止不登录就能访问接口。
-
技术难点
JWT请求流程
- 用户使用账号和密码发出post请求;
- 服务器使用私钥创建一个jwt;
- 服务器返回这个jwt给浏览器;
- 浏览器将该jwt串在请求头中像服务器发送请求;
- 服务器验证该jwt
- 返回响应的资源给浏览器。
2、技术详述,描述你是如何实现和使用该技术的,要求配合代码和流程图详细描述。可以再细分多个点,分开描述各个部分。
-
在pom.xml引入JWT依赖
<dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.4.0</version> </dependency>
-
新建annotation文件夹,自定义两个注解
用来跳过验证的
PassToken
/** * PassToken * 跳过token验证的注解 * */ @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface PassToken { boolean required() default true; }
需要登录才能进行操作的注解
UserLoginToken(后续有需要管理员登录adminLoginToken也是同理)
@Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface UserLoginToken { boolean required() default true; }
-
新建TokenService类生成token
public class TokenService { public String getToken(User user) { Date expiresDate = new Date(System.currentTimeMillis() + EXPIRE_TIME); return JWT.create().withAudience(String.valueOf(user.getUserid())) .sign(Algorithm.HMAC256(user.getPassword())); } }
-
新建interceptor文件,在文件中新建AuthenticationInterceptor拦截器类(userService.findUserById(userId);//这个得自己写)
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"); } User 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("token无效"); } 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 { }
-
配置拦截器,在config文件夹中配置
@Configuration public class InterceptorConfig extends WebMvcConfigurerAdapter { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(authenticationInterceptor()) .addPathPatterns("/**"); // 拦截所有请求,通过判断是否有 @LoginRequired 注解 决定是否需要登录 } @Bean public AuthenticationInterceptor authenticationInterceptor() { return new AuthenticationInterceptor(); } }
-
在util文件中新建TokenUtil接口
public interface TokenUtil { static String getUserIdByRequest(HttpServletRequest httpServletRequest) { String token = httpServletRequest.getHeader("token"); return String.valueOf(JWT.decode(token).getAudience().get(0)); } }
写接口时可通过参数获取userid
String userid = TokenUtil.getAdminIdByRequest(httpServletRequest);
-
写接口是需要通过token验证在前加@UserLoginToken
@UserLoginToken public AjaxResponse getNameByToken(HttpServletRequest httpServletRequest) { String userid = TokenUtil.getAdminIdByRequest(httpServletRequest); ... }
登录接口的话就加@PassToken跳过验证
3、技术使用中遇到的问题和解决过程。
设置过期时间问题
public class TokenService {
//设置过期时间
private static final long EXPIRE_TIME = 7 * 24 * 3600 * 1000;//7天
public String getToken(User user) {
Date expiresDate = new Date(System.currentTimeMillis() + EXPIRE_TIME);
return JWT.create().withAudience(String.valueOf(user.getUserid()))
.withExpiresAt(expiresDate)
.sign(Algorithm.HMAC256(user.getPassword()));
}
}
4、进行总结。
总体来说不是很难,也没叫你去理解JWT解码,就是要配置很多,但是明白流程的话,看代码会更为简单易懂。
5、列出参考文献、参考博客(标题、作者、链接)。
作者:意识流丶
链接:https://www.jianshu.com/p/e88d3f8151db
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。