了解jwt
Json web token (JWT),通信双方之间以json对象形式安全的传递信息,JWT可以使用HMAC算法或者是RSA的公私秘钥对进行签名,可以叫做是调用接口的令牌
操作流程
- 用户使用账号发送请求调用接口
- 服务器使用私钥创建一个jwt
- 服务器返回这个jwt给浏览器
- 浏览器将该jwt串在请求头中像服务器发送请求
- 服务器验证该jwt
- 返回响应的资源给浏览器
具体步骤
- 引入JWT依赖
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.4.0</version>
</dependency>
- 需要自定义两个注解
用来跳过验证的PassToken
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface UserLoginToken {
boolean required() default true;
}
- 需要写一个拦截器去获取token并验证token
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("401");
}
return true;
}
}
return true;
}
- 配置拦截器
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authenticationInterceptor())
.addPathPatterns("/**");
}
@Bean
public AuthenticationInterceptor authenticationInterceptor() {
return new AuthenticationInterceptor();
}
}
- 写获取token的接口
@PostMapping("/login")
public Object login(String username,String password){
JSONObject jsonObject=new JSONObject();
UserDO user = userService.findByName(username);
if(user==null){
jsonObject.put("message","登录失败,用户不存在");
return jsonObject;
}else {
String token="";
token= JWT.create().withAudience(user.getUserId().toString())
.sign(Algorithm.HMAC256(user.getPassword()));
jsonObject.put("token", token);
jsonObject.put("user", user);
return jsonObject;
}
}
- 调用接口验证 得到token
- 将token放在 headers里
此时如果不加token到headers里,就得不到数据, 对应的controller接口里也要有注解@UserLoginToken,会验证token,@PassToken,不会验证token.
另外需要注意的是AuthenticationInterceptor拦截器中 HandlerMethod包一定要导对,不然会出错.org.springframework.web.method.HandlerMethod;本人就是一直出错 - -