Spring项目使用JWT进行后端鉴权
- 添加需要使用的新依赖项
<dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>3.10.3</version></dependency><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.24</version></dependency>
- 添加访问路径前缀配置
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic void configurePathMatch(PathMatchConfigurer configurer) {configurer.addPathPrefix("/api",clazz ->clazz.isAnnotationPresent(RestController.class));}
}
- 将原理@Controller类中的@Controller注解替换为@RestController;
- JWT鉴权原理如下
https://blog.51cto.com/u_9806927/12294431 - 在项目中添加JWT工具
package com.example.demo.common;import cn.hutool.core.date.DateUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.example.demo.service.UserService;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Component;import java.util.Date;@Component
public class JwtTokenUtils {private static UserService staticUserService;@Resourceprivate UserService userService;@PostConstructpublic void setUserService() {userService = staticUserService;}public static String genToken(String account, String password) {return JWT.create().withAudience(account).withExpiresAt(DateUtil.offsetHour(new Date(), 2)).sign(Algorithm.HMAC256(password));}}
- 重构User类,重写登录接口,当用户登录成功后,将token一起返回给前端;
- 在项目中添加拦截器,用于校验JWTtoken的正确性
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.example.demo.entity.User;
import com.example.demo.service.UserService;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;@Component
public class JwtInterceptor implements HandlerInterceptor {private static final Logger log = LoggerFactory.getLogger(JwtInterceptor.class);@Resourceprivate UserService userService;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response,Object handler) throws Exception {String token = request.getHeader("token");if(StrUtil.isBlank(token)){token = request.getParameter("token");}if(StrUtil.isBlank(token)){throw new Exception("登录状态异常,请重新登录");}String account;User user = null;try{account = JWT.decode(token).getAudience().get(0);user = userService.findUserByAccount(account);}catch (Exception e){log.error("无效tonken,token:" + token);}if(user == null){throw new Exception("用户不存在,请重新登录");}try{JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getPassword())).build();jwtVerifier.verify(token);}catch (JWTVerificationException e){throw new Exception("token验证失败,请重新登录");}return true;}
}
- 在拦截器配置到对应的接口上面
import jakarta.annotation.Resource;
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;@Configuration
public class WebConfig implements WebMvcConfigurer {@Resourceprivate JwtInterceptor jwtInterceptor;@Overridepublic void configurePathMatch(PathMatchConfigurer configurer) {configurer.addPathPrefix("/api",clazz ->clazz.isAnnotationPresent(RestController.class));}@Overridepublic void addInterceptors(InterceptorRegistry registry){registry.addInterceptor(jwtInterceptor).addPathPatterns("/api/**").excludePathPatterns("/api/user/login").excludePathPatterns("/api/user/register");}
}