参考文章:https://www.jianshu.com/p/e88d3f8151db
1、添加项目依赖
implementation 'com.auth0:java-jwt:3.4.1'
2、新建JWT工具类JwtUtil
public class JwtUtil {
// 过期时间120分钟
public static final long EXPIRE_TIME = 120 * 60 * 1000;
/**
* 校验token是否正确
*
* @param token 密钥
* @param secret 用户的密码
* @return 是否正确
*/
public static boolean verify(String token, String username, String secret) {
try {
// 根据密码生成JWT效验器
Algorithm algorithm = Algorithm.HMAC256(secret);
JWTVerifier verifier = JWT.require(algorithm).withClaim("username", username).build();
// 效验TOKEN
DecodedJWT jwt = verifier.verify(token);
return true;
} catch (Exception exception) {
return false;
}
}
/**
* 获得token中的信息无需secret解密也能获得
*
* @return token中包含的用户名
*/
public static String getUsername(String token) {
try {
DecodedJWT jwt = JWT.decode(token);
return jwt.getClaim("username").asString();
} catch (JWTDecodeException e) {
return null;
}
}
/**
* 生成签名,5min后过期
*
* @param username 用户名
* @param secret 用户的密码
* @return 加密的token
*/
public static String sign(String username, String secret) {
Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
Algorithm algorithm = Algorithm.HMAC256(secret);
// 附带username信息
return JWT.create().withClaim("username", username).withExpiresAt(date).sign(algorithm);
}
}
3、编写Token验证拦截器
public class AuthenticationInterceptor implements HandlerInterceptor {
@Resource
private UserRepository userRepository;
@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 username = JwtUtil.getUsername(token);
if (username == null) {
throw new RuntimeException("获取用户名失败,请重新登录");
}
SysUser user = userRepository.findByUsername(username);
if (user == null) {
throw new RuntimeException("用户不存在,请重新登录");
}
// 验证 token
return JwtUtil.verify(token, user.getUsername(), user.getPassword());
}
}
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 {
}
}
4、配置拦截器
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authenticationInterceptor())
.addPathPatterns("/**"); // 拦截所有请求,通过判断是否有 @LoginRequired 注解 决定是否需要登录
}
@Bean
public AuthenticationInterceptor authenticationInterceptor() {
return new AuthenticationInterceptor();
}
}
5、全局异常捕捉
@ControllerAdvice
public class GloablExceptionHandler {
@ResponseBody
@ExceptionHandler(Exception.class)
public Result<String> handleException(Exception e) {
Result<String> result = new Result<>();
String msg = e.getMessage();
if (msg == null || msg.equals("")) {
msg = "服务器出错";
}
result.error(msg);
return result;
}
}
6、自定义两个注解
-跳过验证的PassToken
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface PassToken {
boolean required() default true;
}
-登录才能进行操作的注解UserLoginToken
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface UserLoginToken {
boolean required() default true;
}
7、用户登录UserController
@RestController
@RequestMapping("/user")
public class UserController {
@Resource
private UserRepository userRepository;
@RequestMapping(value = "/login", method = RequestMethod.POST)
public Result<String> userLogin(@RequestBody LoginModel loginModel) {
System.out.println(loginModel.getUsername() + "/" + loginModel.getPassword());
Result<String> result = new Result<>();
SysUser user = userRepository.findByUsername(loginModel.getUsername());
if (user != null && loginModel.getPassword().equals(user.getPassword())) {
user.setLoginTime(new Date());
userRepository.saveAndFlush(user);
String token = JwtUtil.sign(loginModel.getUsername(), loginModel.getPassword());
System.out.println(token);
result.setResult(token);
result.success("登录成功");
} else {
result.error("用户名或密码错误");
}
return result;
}
@UserLoginToken
@GetMapping("/getMessage")
public String getMessage(){
return "你已通过验证";
}
}
网友评论