SpringBoot集成jwt,实现token验证
本文使用jwt的方式实现了token验证
pom文件
<!-- JWT token认证--><dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>3.10.3</version></dependency>
GlobalExceptionHandler
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;/*** @Author majinzhong* @Date 2025/2/20 17:05* @Version 1.0*/
@ControllerAdvice
public class GlobalExceptionHandler {// 捕获ServiceException@ExceptionHandler(ServiceException.class)public ResponseEntity<ErrorResponse> handleServiceException(ServiceException ex) {// 创建一个错误响应对象ErrorResponse errorResponse = new ErrorResponse(ex.getCode(), ex.getMessage());// 返回自定义的错误响应return new ResponseEntity<>(errorResponse, HttpStatus.UNAUTHORIZED); // 401 Unauthorized}// 如果需要,可以添加其他异常的处理逻辑
}// 错误响应类
class ErrorResponse {private int code;private String message;public ErrorResponse(int code, String message) {this.code = code;this.message = message;}// Getter 和 Setter 方法public int getCode() {return code;}public void setCode(int code) {this.code = code;}public String getMessage() {return message;}public void setMessage(String message) {this.message = message;}
}
JwtInterceptor
import cn.hutool.core.util.StrUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.smart.entity.SmartUser;
import com.smart.service.SmartUserService;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;/*** @Author majinzhong* @Date 2025/2/20 16:06* @Version 1.0*/
@Component
@Slf4j
public class JwtInterceptor implements HandlerInterceptor {private static final int ERROR_CODE_401 = 401;@Autowiredprivate SmartUserService userService;@SneakyThrows@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {String token = request.getHeader("token");if (StrUtil.isBlank(token)) {token = request.getParameter("token");}// 执行认证if (StrUtil.isBlank(token)) {throw new ServiceException(ERROR_CODE_401,"无token,请重新登录");}// 获取 token 中的userIdString userId;SmartUser user;try {userId = JWT.decode(token).getAudience().get(0);// 根据token中的userid查询数据库user = userService.getById(Integer.parseInt(userId));} catch (Exception e) {String errMsg = "token验证失败,请重新登录";log.error(errMsg + ", token=" + token, e);throw new ServiceException(ERROR_CODE_401,"token验证失败,请重新登录");}if (user == null) {throw new ServiceException(ERROR_CODE_401,"用户不存在,请重新登录");}try {// 用户密码加签验证 token, 对应TokenUtlis,java中的.sign(Algorithm.HMAC256(sign)); // 以 password 作为 token 的密钥JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getUserPwd())).build();jwtVerifier.verify(token); // 验证token} catch (JWTVerificationException e) {throw new Exception(e);}return true;}
}
ServiceException
/*** @Author majinzhong* @Date 2025/2/20 16:57* @Version 1.0* 自定义业务异常类*/
public class ServiceException extends RuntimeException {// 错误代码private final int code;// 构造方法public ServiceException(int code, String message) {super(message); // 调用父类的构造方法设置异常信息this.code = code; // 设置自定义的错误代码}// 获取错误代码public int getCode() {return code;}@Overridepublic String toString() {return "ServiceException{" +"code=" + code +", message='" + getMessage() + '\'' +'}';}
}
TokenUtils
import cn.hutool.core.util.StrUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.smart.entity.SmartUser;
import com.smart.service.SmartUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;/*** @Author majinzhong* @Date 2025/2/20 16:06* @Version 1.0*/
@Component
@Slf4j
public class TokenUtils {private static SmartUserService staticUserService;@Resourceprivate SmartUserService userService;@PostConstructpublic void setUserService() {staticUserService = userService;}/*** 生成token** @return*/public static String getToken(String userId, String sign) {return JWT.create().withAudience(userId) // 将 user id 保存到 token 里面,作为载荷
// .withExpiresAt(DateUtil.offsetHour(new Date(), 2)) // 2小时后token过期.sign(Algorithm.HMAC256(sign)); // 以 password 作为 token 的密钥}/*** 获取当前登录的用户信息** @return user对象* /admin?token=xxxx*/public static SmartUser getCurrentUser() {String token = null;try {HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();token = request.getHeader("token");if (StrUtil.isBlank(token)) { // 这里青戈写错了,应该是isBlanktoken = request.getParameter("token");}if (StrUtil.isBlank(token)) {log.error("获取当前登录的token失败, token: {}", token);return null;}String userId = String.valueOf(JWT.decode(token).getAudience().get(0));return staticUserService.getById(Integer.valueOf(userId));} catch (Exception e) {log.error("获取当前登录的管理员信息失败, token={}", token, e);return null;}}
}
WebConfig
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;/*** @Author majinzhong* @Date 2025/2/20 16:05* @Version 1.0*/@Configuration
public class WebConfig implements WebMvcConfigurer {@AutowiredJwtInterceptor jwtInterceptor;@Overridepublic void configurePathMatch(PathMatchConfigurer configurer) {// 指定controller统一的接口前缀configurer.addPathPrefix("/", clazz -> clazz.isAnnotationPresent(RestController.class));}// 加自定义拦截器JwtInterceptor,设置拦截规则@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(jwtInterceptor).addPathPatterns("/api/**").excludePathPatterns("/smartUser/login");}}