使用注解统一拦截的方式! 能简的都简了!
JWT的主要应用场景
单点登录,安全性比较高,签名的密钥是项目自己定的,别人就很难解密!可以确保发送者发送的信息是没有经过伪造的。
说说在前端的使用叭,前端在登录成功后把token存起来(cookie/Storage)统一管理,在请求后端接口时把token带上就ok
SpringBoot和JWT的集成
1、引入JWT依赖
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.4.0</version>
</dependency>
2、自定义两个注解
2.1 用于跳过验证的PassToken的注解(如登录接口)
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface PassToken {
boolean required() default true;
}
2.2 需登录并验证token的注解UserLoginToken
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface UserLoginToken {
boolean required() default true;
}
3、 定义一个Entity
@Data
public class User {
String Id;
String username;
String password;
}
4 、Token的生成方法
@Configuration
@ComponentScan(basePackages="com.xxx.xxx")
public class TokenCreate {
public String getToken(User user) {
String token="";
token= JWT.create().withAudience(user.getUserPhone())
.sign(Algorithm.HMAC256(user.getPassword()));
return token;
}
}
5 、获取请求头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;
}
@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 {
}
5.1 配置
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authenticationInterceptor())
.addPathPatterns("/**");
}
@Bean
public AuthenticationInterceptor authenticationInterceptor() {
return new AuthenticationInterceptor();
}
}
6 、登录接口
@RestController
@RequestMapping("api")
public class UserApi {
@Autowired
UserService userService;
@Autowired
TokenService tokenCreate;
//登录
@PassToken //免token验证注解
@PostMapping("/login")
public Object login(@RequestBody User user){
JSONObject jsonObject=new JSONObject();
User userForBase=userService.findByUsername(user);
if(userForBase==null){
jsonObject.put("message","登录失败,账号不存在");
return jsonObject;
}else {
if (!userForBase.getPassword().equals(user.getPassword())){
jsonObject.put("message","登录失败,账号信息错误!");
return jsonObject;
}else {
//登录成功 创建token并返回
jsonObject.put("token", tokenCreate.getToken(userForBase));
jsonObject.put("user", userForBase);
return jsonObject;
}
}
}
@UserLoginToken // 拦截获取header的token进行检验
@GetMapping("/getMessage")
public String getMessage(){
return "棒!已通过验证!";
}
}