SpringBoot使用JWT作为Token实现前后端分离登录
程序员文章站
2022-03-15 11:42:59
...
JWT就不多介绍了
传统的shiro和SpringSecurity安全框架需要Session,重启后Session会丢失,或者将Session存入redis也行,但是相对比较繁琐。利用JWT可以很轻松的实现Token的认证,在前后端分离的情况下,JWT也显得非常的简易。
依赖
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.4.0</version>
</dependency>
登录请求生成token,第一个参数传入ID,表明是哪个用户,第二个参数是对token进行加密,我们都用密码进行加密。
String token = JWT.create().withAudience(user.getId() + "")
.sign(Algorithm.HMAC256(user.getPwd()));
写一个notoken注解,此注解适用于方法上,用来表明某个请求不需要token
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface NoToken {
boolean required() default true;
}
然后利用拦截器进行拦截所有的请求
public class AuthenticationInterceptor implements HandlerInterceptor {
@Autowired
private UserMapper userMapper;
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
Object object) throws Exception {
// 如果不是映射到方法直接通过
if (!(object instanceof HandlerMethod)) {
return true;
}
HandlerMethod handlerMethod = (HandlerMethod) object;
Method method = handlerMethod.getMethod();
// 检查是否有passtoken注释,有则跳过认证
if (method.isAnnotationPresent(NoToken.class)) {
NoToken passToken = method.getAnnotation(NoToken.class);
if (passToken.required()) {
return true;
}
} else {
String token = httpServletRequest.getHeader("Authorization");
// Token不存在
if (token == null) {
throw new NeedLoginException();
}
// 获取用户ID,如果出错抛异常
Integer userId;
try {
userId = AuthUtils.getUserId(httpServletRequest);
} catch (JWTDecodeException j) {
throw new NeedLoginException();
}
Staff user = userMapper.selectByPrimaryKey(userId);
if (user == null) {
throw new NeedLoginException();
}
// 验证Token是否有效
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getStaffPwd() + "")).build();
try {
jwtVerifier.verify(token);
} catch (JWTVerificationException e) {
throw new NeedLoginException();
}
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 {
}
}
将拦截器加入到Bean中
@Configuration
public class InterceptorConfig extends WebMvcConfigurerAdapter {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authenticationInterceptor()).addPathPatterns("/**"); // 拦截所有请求,通过判断是否有 @LoginRequired 注解
}
@Bean
public AuthenticationInterceptor authenticationInterceptor() {
return new AuthenticationInterceptor();
}
}
从请求头获取Token解析用户ID
public class AuthUtils {
public static Integer getUserId(HttpServletRequest req) {
String token = req.getHeader("Authorization");
String userId = JWT.decode(token).getAudience().get(0);
return Integer.parseInt(userId);
}
}
这样就可以实现登录了。
如果有哪些请求不需要Token的话,直接可以加上注解@NoToken,在拦截器中判断如果遇到此注解,则不会进行判断Token
上一篇: 自定义异常类的简单运用
下一篇: 关于Session认证的探索