• Springboot中认证和授权的实现(使用jwt)


    1、jwt验证过程
    (1)、在前端用户通过登录页面将用户名和密码发送给后台(建议使用https协议(SSL加密),避免敏感信息被嗅探);
    (2)、后台核对用户名和密码后,将用户ID等非敏感信息作为负载,将其与Header分别进行Base64编码,然后拼接后签名,生成token字符串;
    (3)、后台将token字符串返回给前端;
    (4)、前端每次请求时将token放入http Header的Authorization字段。
    (5)、后台检验是否存在,如果存在验证token的有效性,譬如签名是否正确,是否过期,token接收方是否是自己等。
    (6)、验证通过后后台根据用户权限进行逻辑操作,否则提示异常信息。
    (7)、返回响应结果。
    2、token介绍
    (1)、令牌组成
    Header.Payload.SIgnature(xxxxx.yyyyy.zzzzz)
    Header为标题头、Payload为有效载荷、Signature为签名;
    (2)、Header
    标题头由两部分组成:即令牌的类型和所使用的签名算法(如HMAC、SHA256或RSA),然后进行Base64编码生成Header。
    Base64是一种编码,不是加密过程,它可以翻译成原来的样子,如:
    {
    “alg”: “RSA”,
    “typ”: “JWT”
    }
    (3)、Payload
    有效负荷包含声明,声明有关实体(通常是用户)和其它数据,然后进行Base64编码生成Payload。
    Base64是一种编码,不是加密过程,它可以翻译成原来的样子,如:
    {
    “id”: “12”,
    “name”: “husan”,
    “admin”: true
    }
    (4)、Signature
    对编码后的Header、Payload及设定的一个密钥按照指定签名算法进行加密,生成签名。
    RSA(base64UrlEncode(Header)+“.”+base64UrlEncode(payload),secret);
    (5)、签名目的
    对标题头和有效负荷内容进行签名,防止内容被篡改。
    (6)、信息安全
    Base64是一种编码,是可逆的,所以信息是暴露的,不能在有效负荷里加入任何敏感数据。
    jwt适用于向前端传递一些非敏感信息,设计用户认证和授权系统,甚至实现Web应用的单点登录。

    3、代码实现
    (1)、注入依赖

    <dependency>
      <groupId>com.auth0</groupId>
      <artifactId>java-jwt</artifactId>
      <version>3.10.3</version>
    </dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    (2)、实现jwt工具类

    package com.example.utils;
    
    import com.auth0.jwt.JWT;
    import com.auth0.jwt.JWTCreator;
    import com.auth0.jwt.algorithms.Algorithm;
    import com.auth0.jwt.interfaces.DecodedJWT;
    
    import java.util.Calendar;
    import java.util.Map;
    
    public class JWTUtils {
        private static String SECRET = "tokenIsImportant";
    
        /**
         * 生产token
         */
        public static String getToken(Map<String, String> map) {
            JWTCreator.Builder builder = JWT.create();
    
            //payload   将用户信息放到令牌里面
            map.forEach((k, v) -> {
                builder.withClaim(k, v);
            });
    
            Calendar instance = Calendar.getInstance();
            instance.add(Calendar.DATE, 7); //默认7天过期
    
            builder.withExpiresAt(instance.getTime());//指定令牌的过期时间
            String token = builder.sign(Algorithm.HMAC256(SECRET));//签名
            return token;
        }
    
        /**
         * 验证token
         */
        public static DecodedJWT verify(String token) {
            //如果有任何验证异常,此处都会抛出异常
            DecodedJWT decodedJWT = JWT.require(Algorithm.HMAC256(SECRET)).build().verify(token);
            return decodedJWT;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    (3)、编写jwt拦截器

    @Slf4j
    public class JWTInterceptor implements HandlerInterceptor {
    
        @Override
        public boolean preHandle(HttpServletRequest request,
                                 HttpServletResponse response,
                                 Object handler) throws Exception {
    
            //获取请求头中的令牌
            String token = request.getHeader("Authorization");
            log.info("当前token为:{}", Authorization);
    
            Map<String, Object> map = new HashMap<>();
            try {
                JWTUtils.verify(token);
                return true;
            } catch (SignatureVerificationException e) {
                e.printStackTrace();
                map.put("msg", "签名不一致");
            } catch (TokenExpiredException e) {
                e.printStackTrace();
                map.put("msg", "令牌过期");
            } catch (AlgorithmMismatchException e) {
                e.printStackTrace();
                map.put("msg", "算法不匹配");
            } catch (InvalidClaimException e) {
                e.printStackTrace();
                map.put("msg", "失效的payload");
            } catch (Exception e) {
                e.printStackTrace();
                map.put("msg", "token无效");
            }
    
            map.put("state", false);
    
            //响应到前台: 将map转为json
            String json = new ObjectMapper().writeValueAsString(map);
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().println(json);
            return false;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    (4)、编写jwt配置类

    @Configuration
    public class InterceptorConfig implements WebMvcConfigurer {
    
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            // addInterceptor 就是加过滤器
            registry.addInterceptor(new JWTInterceptor())
                    .addPathPatterns("/user/test")
                    .excludePathPatterns("/user/login")
            ;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    (5)、写控制器调用

    @RestController
    @Slf4j
    @RequestMapping("/user")
    public class UserController {
    
        @Resource
        private UserService userService;
    
        @GetMapping("/login")
        public Map<String, Object> login(User user) {
            log.info("用户名:{}", user.getName());
            log.info("password: {}", user.getPassword());
    
            Map<String, Object> map = new HashMap<>();
    
            try {
                User userDb = userService.login(user);
    	    if(userDb != null){
    	      Map<String, String> payload = new HashMap<>();
                  payload.put("id", userDb.getId());
                  payload.put("name", userDb.getName());
                  String token = JWTUtils.getToken(payload);
    
                  map.put("state", true);
                  map.put("msg", "登录成功");
                  map.put("token", token);
                  return map;
                }
                
            } catch (Exception e) {
                e.printStackTrace();
            }
    	map.put("state", false);
            map.put("msg", e.getMessage());
            map.put("token", "");
            return map;
        }
    
        @PostMapping("/test")
        public Map<String, Object> test(HttpServletRequest request) {
            String token = request.getHeader("token");
            DecodedJWT verify = JWTUtils.verify(token);
            String id = verify.getClaim("id").asString();
            String name = verify.getClaim("name").asString();
            log.info("用户id:{}", id);
            log.info("用户名: {}", name);
    
            //TODO 业务逻辑
            Map<String, Object> map = new HashMap<>();
            map.put("state", true);
            map.put("msg", "请求成功");
            return map;
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
  • 相关阅读:
    Polygon zkEVM节点代码解析
    HTML5期末大作业——HTML+CSS+JavaScript平遥古城旅游景点介绍(6页)
    驱动开发,IO多路复用实现过程,epoll方式
    《暴走IT》第5话:“裸泳”的办公软件
    【linux】linux实操篇之任务调度
    如何使用API接口对接淘宝获取店铺销量排序,店铺名称等参数
    Rethinking LiDAR Object Detection in adverse weather conditions
    手把手教你:LLama2原始权重转HF模型
    Python 基础(十四):类和对象
    论文解读(SUBLIME)《Towards Unsupervised Deep Graph Structure Learning》
  • 原文地址:https://blog.csdn.net/qq_27474555/article/details/133378162