• 分布式session解决方案 — — JWT(生成token)


    JWT 跨域认证解决方案

    1 介绍

    • JWT(JSON Web Token)是目前最流行的跨域认证解决方案,是一种基于Token的认证授权机制,JWT本身也是Token,是一种规范化之后的JSON结构的Token。
    • JWT自身包含了验证所需要的所有信息,因此,我们的服务器不需要存储Session信息(其他解决方案:hash、session共享),增加了系统的可用性和伸缩性,大大减轻了服务端的压力。
    • JWT更符合RESTFul API的无状态原则
    • JWT认证可以有效避免CSRF(跨站请求伪造攻击),因为JWT一般是存在在localStorage中,使用JWT进行身份验证的过程中不会涉及到Cookie

    2 组成部分

    JWT本质就是一组字符串,通过(.)切分成三个为Base64编码的部分:

    1. Header:描述JWT元数据,定义生成签名的算法及Token类型
    2. Payload:存放实际要传递的数据
    3. Signature(签名):服务器通过Payload、Header和一个密钥(Secret)使用Header里面指定的签名算法(默认是HMAC SHA256)

    实例:用点分割,分为三部分
    在这里插入图片描述

    3 JWT工具类的编写(企业开发)

    3.1 定义对应编码及盐值(加密时)

    //定义对应的编码算法
    static SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
    //盐值,盐值随意,看公司要求【此处我采用UUID】
    static String secretKey = "d8de020f63754a9fa746ea74b831afc3";
    
    • 1
    • 2
    • 3
    • 4

    3.2 获取key

    //获取key(指定算法和盐值的key对象)
    private static Key generateKey(){
        //将盐值转成字节
        byte[] bytes = DatatypeConverter.parseBase64Binary(secretKey);
        //根据算法和盐值生成对应的key值
        Key key = new SecretKeySpec(bytes, signatureAlgorithm.getJcaName());
        return key;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    3.3 生成token(generatorToken)

    /**
     * 将我们的数据使用JWT的方式变成一个token xxx.yyy.zzz
     * @param payLoad   负载(数据信息)
     * @return
     */
    public static String generatorToken(Map<String, String> payLoad){
        ObjectMapper objectMapper = new ObjectMapper();
        try{
            //构建jwt生成器
            JwtBuilder builder = Jwts.builder();
            //将负载信息设置到jwt生成器中
            JwtBuilder jwtBuilder = builder.setPayload(objectMapper.writeValueAsString(payLoad));
            //根据签名算法和key值,生成新的jwtBuilder
            JwtBuilder jwtBuilder1 = jwtBuilder.signWith(signatureAlgorithm, generateKey());
            String token = jwtBuilder1.compact();
            return token;
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    3.4 获取token中的body信息

    /**
      * 根据指定的token, 返回对应的body信息
      * @param token
      * @return
      */
     public static Claims phaseTokenGetBody(String token){
         JwtParser jwtParser = Jwts.parser().setSigningKey(generateKey());
         Jws<Claims> claimsJws = jwtParser.parseClaimsJws(token);
         Claims body = claimsJws.getBody();//主要存放的信息
         return body;
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    3.5 获取token中的signature信息

    /**
      * 根据指定的token获取签名信息
      * @param token
      * @return
      */
     public static String phaseTokenGetSignature(String token){
         JwtParser jwtParser = Jwts.parser().setSigningKey(generateKey());
         Jws<Claims> claimsJws = jwtParser.parseClaimsJws(token);
         String signature = claimsJws.getSignature();
         return signature;
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    3.6 获取token中的头信息

    /**
     * 根据指定的token获取头信息
     * @param token
     * @return
     */
    public static JwsHeader phaseTokenGetHeader(String token){
        //获取解析器
        JwtParser parser = Jwts.parser();
        //设置签名key(盐值)
        parser = parser.setSigningKey(generateKey());
        //解析token
        Jws<Claims> claimsJws = parser.parseClaimsJws(token);
        JwsHeader header = claimsJws.getHeader();
        return header;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    3.7 测试

    ①在map中存入自己的数据,调用自定义API生成对应token

    public static void main(String[] args) {
        //随机获取盐值
    //        System.out.println(UUID.randomUUID().toString().replaceAll("-", ""));
        Map<String, String> payLoad = new HashMap<>();
        payLoad.put("name", "curry");
        String s = generatorToken(payLoad);
        //eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiY3VycnkifQ.Sf3GiF3p56nLzoAxEHLXcAckPmmPTtecj1_lGT9oV8s
        System.out.println(s);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    ②在jwt官网https://jwt.io/中进行解析,也可以调用自己的API进行解析
    在这里插入图片描述
    调用自己API:

    //调用自定义API获取结果
    Claims claims = phaseTokenGetBody(s);
    //{name=curry}
    
    • 1
    • 2
    • 3

    ③如果所给token有误,则会报错

    Exception in thread "main" io.jsonwebtoken.SignatureException: JWT signature does not match locally computed signature. JWT validity cannot be asserted and should not be trusted.
    
    • 1

    4 全部代码包含测试

    package com.zi.api.commons.util;
    
    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import io.jsonwebtoken.*;
    
    import javax.crypto.spec.SecretKeySpec;
    import javax.xml.bind.DatatypeConverter;
    import java.security.Key;
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * 生成jwt工具类
     */
    public class JJWTRootUtils {
    
        //定义对应的编码算法
        static SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        //盐值
        static String secretKey = "d8de020f63754a9fa746ea74b831afc3";
    
        //获取key(指定算法和盐值的key对象)
        private static Key generateKey(){
            //将盐值转成字节
            byte[] bytes = DatatypeConverter.parseBase64Binary(secretKey);
            //根据算法和盐值生成对应的key值
            Key key = new SecretKeySpec(bytes, signatureAlgorithm.getJcaName());
            return key;
        }
    
        /**
         * 将我们的数据使用JWT的方式变成一个token xxx.yyy.zzz
         * @param payLoad   负载(数据信息)
         * @return
         */
        public static String generatorToken(Map<String, String> payLoad){
            ObjectMapper objectMapper = new ObjectMapper();
            try{
                //构建jwt生成器
                JwtBuilder builder = Jwts.builder();
                //将负载信息设置到jwt生成器中
                JwtBuilder jwtBuilder = builder.setPayload(objectMapper.writeValueAsString(payLoad));
                //根据签名算法和key值,生成新的jwtBuilder
                JwtBuilder jwtBuilder1 = jwtBuilder.signWith(signatureAlgorithm, generateKey());
                String token = jwtBuilder1.compact();
                return token;
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
            return null;
        }
    
        /**
         * 根据指定的token, 返回对应的body信息
         * @param token
         * @return
         */
        public static Claims phaseTokenGetBody(String token){
            JwtParser jwtParser = Jwts.parser().setSigningKey(generateKey());
            Jws<Claims> claimsJws = jwtParser.parseClaimsJws(token);
            Claims body = claimsJws.getBody();//主要存放的信息
            return body;
        }
    
        /**
         * 根据指定的token获取签名信息
         * @param token
         * @return
         */
        public static String phaseTokenGetSignature(String token){
            JwtParser jwtParser = Jwts.parser().setSigningKey(generateKey());
            Jws<Claims> claimsJws = jwtParser.parseClaimsJws(token);
            String signature = claimsJws.getSignature();
            return signature;
        }
    
    
        /**
         * 根据指定的token获取头信息
         * @param token
         * @return
         */
        public static JwsHeader phaseTokenGetHeader(String token){
            //获取解析器
            JwtParser parser = Jwts.parser();
            //设置签名key(盐值)
            parser = parser.setSigningKey(generateKey());
            //解析token
            Jws<Claims> claimsJws = parser.parseClaimsJws(token);
            JwsHeader header = claimsJws.getHeader();
            return header;
        }
    
    
        public static void main(String[] args) {
            //随机获取盐值
    //        System.out.println(UUID.randomUUID().toString().replaceAll("-", ""));
            Map<String, String> payLoad = new HashMap<>();
            payLoad.put("name", "curry");
            String s = generatorToken(payLoad);
            //eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiY3VycnkifQ.Sf3GiF3p56nLzoAxEHLXcAckPmmPTtecj1_lGT9oV8s
            System.out.println(s);
    
            //调用自定义API获取结果
            Claims claims = phaseTokenGetBody(s);
            //{name=curry}
            System.out.println(claims);
        }
    
    }
    
    
    • 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
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
  • 相关阅读:
    Elasticsearch深入理解(十三)——Index更换字段类型的三种方式
    安全性第一!OpenWRT配置SFTP远程文件传输,实现数据安全保护
    前端学习笔记01
    金仓数据库KingbaseES数据库参考手册(动态性能视图3.3. sys_stat_wal_receiver )
    港联证券:股票浮筹比例的指标怎么用?
    金仓数据库KingbaseES客户端应用参考手册--19. vacuumlo
    CURL踩坑记录
    前端框架的演进之路:从静态网页到现代交互体验的探索
    2024年宝鸡市国家级、省级、市级科技企业孵化器申报奖励补贴标准及申报条件
    初识form表单
  • 原文地址:https://blog.csdn.net/weixin_45565886/article/details/126557256