经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Spring Boot » 查看文章
在 SpringBoot 项目中简单实现 JWT 验证
来源:cnblogs  作者:拉克斯文  时间:2023/2/8 8:57:59  对本文有异议

使用 SpringBoot 提供 api 的时候,我更喜欢使用 jwt 的方式来做验证。网上有会多 Spring Security 整合 jwt 的,也有 Shiro 整合 jwt 的,感觉有点复杂。这里分享一下自己在项目中的简单实现。

依赖包

除了 SpringBoot 基本的依赖,需要一个生成 jwt 和序列化的包。生成 jwt 的包依赖很多,因为我项目里使用了 hutool 这个包,就只用用它了。

  1. <dependency>
  2. <groupId>cn.hutool</groupId>
  3. <artifactId>hutool-all</artifactId>
  4. <version>5.8.9</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>cn.hutool</groupId>
  8. <artifactId>hutool-all</artifactId>
  9. <version>5.8.9</version>
  10. </dependency>

jwt用户模型

定义一个 Jwt 的 sub 字段模型,存储用户:

  1. import lombok.Data;
  2. import org.springframework.web.context.request.RequestAttributes;
  3. import org.springframework.web.context.request.RequestContextHolder;
  4. import org.springframework.web.context.request.ServletRequestAttributes;
  5. import javax.servlet.http.HttpServletRequest;
  6. @Data
  7. public class JwtUser {
  8. /**
  9. * 用户编号
  10. */
  11. private Integer id;
  12. /**
  13. * 用户名
  14. */
  15. private String name;
  16. /**
  17. * 角色
  18. */
  19. private String role;
  20. /**
  21. * 获取当前请求用户
  22. * @return
  23. */
  24. public static JwtUser getCurrentUser() {
  25. RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
  26. HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
  27. return (JwtUser) request.getAttribute("user");
  28. }
  29. }

验证注解

定义一个用于请求类和方法的注解

  1. import java.lang.annotation.*;
  2. @Inherited
  3. @Target({ElementType.TYPE,ElementType.METHOD})
  4. @Retention(RetentionPolicy.RUNTIME)
  5. public @interface Authorize {
  6. /**
  7. * 是否匿名可以访问
  8. * @return
  9. */
  10. boolean anonymous() default false;
  11. /**
  12. * 角色
  13. * @return
  14. */
  15. String[] roles() default {};
  16. }

JWT 帮助类

用于生成 jwt 和 解析 JwtUser 对象。

  1. import cn.hutool.jwt.JWT;
  2. import cn.hutool.jwt.JWTUtil;
  3. import cn.hutool.jwt.signers.JWTSigner;
  4. import cn.hutool.jwt.signers.JWTSignerUtil;
  5. import com.google.gson.Gson;
  6. import com.mpyf.xapi.security.JwtUser;
  7. import lombok.var;
  8. import java.util.Date;
  9. import java.util.HashMap;
  10. import java.util.Map;
  11. import java.util.UUID;
  12. public class JwtTokenUtils {
  13. public static final String SECRET = "your_secret";
  14. public static final String ISS = "com.your.cn";
  15. private static final int EXPIRATIONHOURS = 24; //过期时间24小时
  16. //创建token
  17. public static String createToken(JwtUser user) {
  18. return createToken(user, EXPIRATIONHOURS);
  19. }
  20. public static String createToken(JwtUser user, int hours) {
  21. String subJson = new Gson().toJson(user);
  22. JWTSigner jwtSigner = JWTSignerUtil.hs512(SECRET.getBytes());
  23. JWT jwt = JWT.create().setSigner(jwtSigner);
  24. jwt
  25. .setJWTId(UUID.randomUUID().toString().replace("-", ""))
  26. .setSubject(subJson) //用户信息
  27. .setIssuer(ISS) //签发者
  28. //.setAudience("受众")
  29. //.setNotBefore(new Date())
  30. .setIssuedAt(new Date())
  31. .setExpiresAt(new Date(System.currentTimeMillis() + hours * 3600 * 1000));
  32. return jwt.sign();
  33. }
  34. public static JwtUser getUser(String token) {
  35. if (StringHelper.isNullOrEmpty(token)) return null;
  36. var jwt = JWTUtil.parseToken(token);
  37. JWTSigner jwtSigner = JWTSignerUtil.hs512(SECRET.getBytes());
  38. jwt.setSigner(jwtSigner);
  39. if (jwt.validate(10)) {
  40. var subJson = jwt.getPayload("sub").toString();
  41. JwtUser user = new Gson().fromJson(subJson, JwtUser.class);
  42. return user;
  43. } else {
  44. return null;
  45. }
  46. }
  47. }

验证拦截器

定义jwt的验证拦截器,从请求头获取 token 解析并验证。

  1. import com.mpyf.xapi.helper.JwtTokenUtils;
  2. import com.mpyf.xapi.helper.StringHelper;
  3. import org.springframework.stereotype.Component;
  4. import org.springframework.web.method.HandlerMethod;
  5. import org.springframework.web.servlet.HandlerInterceptor;
  6. import javax.servlet.http.HttpServletRequest;
  7. import javax.servlet.http.HttpServletResponse;
  8. import java.util.Arrays;
  9. /**
  10. * jwt 验证拦截器
  11. */
  12. @Component
  13. public class JwtAuthInterceptor implements HandlerInterceptor {
  14. @Override
  15. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
  16. //Authorization:Bearer+空格+token
  17. String token = request.getHeader("Authorization");
  18. if (token != null) {
  19. token = token.replace("Bearer ", "");
  20. }
  21. //处理模拟登录的jwt
  22. if (StringHelper.isNullOrEmpty(token)) {
  23. token = request.getParameter("jwt");
  24. }
  25. if (StringHelper.isNullOrEmpty(token)) {
  26. //兼容从请求参数传token
  27. Object jwt = request.getAttribute("jwt");
  28. if (jwt != null) {
  29. token = jwt.toString();
  30. }
  31. }
  32. JwtUser user = JwtTokenUtils.getUser(token);
  33. request.setAttribute("user", user);
  34. if (handler instanceof HandlerMethod) {
  35. HandlerMethod h = (HandlerMethod) handler;
  36. Authorize authorize = h.getMethodAnnotation(Authorize.class);
  37. if (authorize == null) {
  38. authorize = h.getMethod().getDeclaringClass().getAnnotation(Authorize.class);
  39. }
  40. //如果没有Authorize或者可以匿名访问,直接返回
  41. if (authorize != null && !authorize.anonymous()) {
  42. {
  43. if (user == null) {
  44. response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
  45. return false;
  46. } else if (authorize.roles() != null && authorize.roles().length > 0 &&
  47. Arrays.stream(authorize.roles()).allMatch(s -> !s.equalsIgnoreCase(user.getRole()))) {
  48. //没权限
  49. response.sendError(HttpServletResponse.SC_FORBIDDEN);
  50. return false;
  51. }
  52. }
  53. }
  54. }
  55. return true;
  56. }
  57. }

注册拦截器

在 WebMvc 配置中注册拦截器,并支持跨域请求

  1. import com.mpyf.xapi.security.JwtAuthInterceptor;
  2. import org.springframework.beans.factory.annotation.Autowired;
  3. import org.springframework.context.annotation.Configuration;
  4. import org.springframework.web.servlet.config.annotation.*;
  5. @Configuration
  6. public class WebMvcConfig implements WebMvcConfigurer {
  7. @Autowired
  8. JwtAuthInterceptor jwtAuthInterceptor;
  9. @Override
  10. public void addInterceptors(InterceptorRegistry registry) {
  11. registry.addInterceptor(jwtAuthInterceptor).addPathPatterns("/api/**");
  12. WebMvcConfigurer.super.addInterceptors(registry);
  13. }
  14. @Override
  15. public void addCorsMappings(CorsRegistry registry) {
  16. registry.addMapping("/api/**")
  17. .allowedOriginPatterns("*")
  18. .allowedMethods("*")
  19. .allowedHeaders("*")
  20. //.maxAge(3600)
  21. .allowCredentials(true);
  22. WebMvcConfigurer.super.addCorsMappings(registry);
  23. }
  24. }

Controller中使用

  1. @RestController
  2. @RequestMapping("/api/test")
  3. @Authorize(roles = {"admin", "user"})
  4. public class TestController {
  5. @GetMapping("admin_and_user")
  6. public String admin_and_user(){
  7. return "admin 和 user 角色都可以访问";
  8. }
  9. @GetMapping("admin_only")
  10. @Authorize(roles = "admin") //覆盖Controller的设置
  11. public String admin_only(){
  12. return "只有 admin 角色可以访问";
  13. }
  14. @GetMapping("public_all")
  15. @Authorize(anonymous = true)
  16. public String public_all(){
  17. return "匿名可以访问";
  18. }
  19. }

不用 Spring Security 和 Shiro ,是不是更简单呢!

原文链接:https://www.cnblogs.com/loogn/p/17099338.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号