• jwt ---- json web token


    一、cookie与session

    image-20220909123942091

    image-20220909123947891

    之后的请求都会携带cooKie和session

    image-20220909123958390

    二、为什么需要jwt

    cookie 和 session的缺点

    • session都存储在服务端内存中
    • 集群环境中需要额外处理,ip_hash,分布式session…
    • Csrf: Cross-site request forgery, cookie被截获后可能发生跨站请求伪造
    • cookie的跨域(前后端分离)读写不方便

    image-20220909222601960

    三、jwt的实现方式

    • 官网: https://jwt.io/
    • Token: 令牌,字符串

    3.1 java-jwt

    <dependency>
        <groupId>com.auth0groupId>
        <artifactId>java-jwtartifactId>
        <version>3.18.2version>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    package com.zs.jwt;
    
    import com.auth0.jwt.JWT;
    import com.auth0.jwt.JWTCreator;
    import com.auth0.jwt.algorithms.Algorithm;
    import com.auth0.jwt.exceptions.AlgorithmMismatchException;
    import com.auth0.jwt.exceptions.InvalidClaimException;
    import com.auth0.jwt.exceptions.SignatureVerificationException;
    import com.auth0.jwt.exceptions.TokenExpiredException;
    import com.auth0.jwt.interfaces.DecodedJWT;
    import org.junit.Test;
    import sun.misc.Cache;
    
    import java.nio.charset.StandardCharsets;
    import java.util.Calendar;
    
    public class JavaJwtTest {
    
        //hmac256摘要算法,跟md5的区别是需要指定一个key(salt盐)
        String key = "123456abc";
    
    
        /**`在这里插入代码片`
         * 测试java-jwt生成token字符串
         */
        @Test
        public void testGenerateToken() {
    
            Calendar calendar = Calendar.getInstance();
            calendar.add(Calendar.SECOND,60);
    
            // claim 声明
            JWTCreator.Builder builder = JWT.create()
                    //payload的内容,由一个个的claim组成
                    .withClaim("userId", 123)
                    .withClaim("userName", "zs")
                    .withClaim("url", "https://jwt.io/")
                    .withExpiresAt(calendar.getTime());
            String token = builder.sign(Algorithm.HMAC256(key));
            System.out.println(token);
        }
    
    
        /**
         * 测试验证令牌
         */
        @Test
        public void testVerifyToken() {
            String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyTmFtZSI6InpzIiwiZXhwIjoxNjYyNzAwNjYzLCJ1c2VySWQiOjEyMywidXJsIjoiaHR0cHM6Ly9qd3QuaW8vIn0.lp7MhOEd7vPM5t4Rosk82PWHfLx1cGn1rG1ZakkDwt8";
            DecodedJWT verify = null;
            try {
                verify = JWT.require(Algorithm.HMAC256(key)).build().verify(token);
            } catch (SignatureVerificationException e) {
                e.printStackTrace();
                System.out.println("签名不一致");
            } catch (TokenExpiredException e) {
                e.printStackTrace();
                System.out.println("令牌过期");
            } catch (AlgorithmMismatchException e) {
                e.printStackTrace();
                System.out.println("签名算法不匹配");
            } catch (InvalidClaimException e) {
                e.printStackTrace();
                System.out.println("payload不可用");
            } catch (Exception e) {
                e.printStackTrace();
                System.out.println("校验失败");
            }
            System.out.println(verify);
    
            if (verify != null) {
                //获取payload里面的聂鑫,注意类型,如果类型不一致,是获取不到的
                Integer userId = verify.getClaim("userId").asInt();
                String userName = verify.getClaim("userName").asString();
                String url = verify.getClaim("url").asString();
    
                System.out.println(userId);
                System.out.println(userName);
                System.out.println(url);
            }
        }
    
    }
    
    • 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

    3.2 jjwt

    <dependency>
       <groupId>io.jsonwebtokengroupId>
       <artifactId>jjwtartifactId>
       <version>0.9.1version>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    package com.zs.jwt;
    
    
    import io.jsonwebtoken.Claims;
    import io.jsonwebtoken.JwtBuilder;
    import io.jsonwebtoken.Jwts;
    import io.jsonwebtoken.SignatureAlgorithm;
    import org.junit.Test;
    
    import java.util.Calendar;
    import java.util.HashMap;
    
    public class JJwtTest {
    
        //hmac256摘要算法,跟md5的区别是需要指定一个key(salt盐)
        String key = "123456abc";
    
    
        /**
         * 测试jjwt生成token字符串
         */
        @Test
        public void testGenerateToken() {
            //过期时间
            Calendar calendar = Calendar.getInstance();
            calendar.add(Calendar.SECOND,60*60);
    
            //创建payload的私有声明(根据特定的业务需要添加)
            HashMap<String, Object> claims = new HashMap<>();
            claims.put("userId",123);
            claims.put("userName","zs");
            claims.put("url","https://jwt.io/");
    
            JwtBuilder builder = Jwts.builder()
                    .setClaims(claims)
                    .setExpiration(calendar.getTime())
                    //设置签名使用的签名算法和签名使用的秘钥
                    .signWith(SignatureAlgorithm.HS256, key);
            String token = builder.compact();
            System.out.println(token);
        }
    
    
    
    
        /**
         * 测试验证令牌
         */
        @Test
        public void testVerifyToken() {
            String token = "eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyTmFtZSI6InpzIiwiZXhwIjoxNjYyNzA0NzEyLCJ1c2VySWQiOjEyMywidXJsIjoiaHR0cHM6Ly9qd3QuaW8vIn0.Nn1HXpdFAtwXLKMnF6mtLuE09IoPwSJ1x3Qxku0OFfU";
            Claims claims = Jwts.parser().setSigningKey(key).parseClaimsJws(token).getBody();
            if (claims != null) {
                //获取payload里面的聂鑫,注意类型,如果类型不一致,是获取不到的
                Integer userId = claims.get("userId",Integer.class);
                String userName = claims.get("userName",String.class);
                String url = claims.get("url",String.class);
    
                System.out.println(userId);
                System.out.println(userName);
                System.out.println(url);
            }
        }
    }
    
    • 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

    四、工具类封装

    4.1 后端工具类

        
        <dependency>
            <groupId>io.jsonwebtokengroupId>
            <artifactId>jjwtartifactId>
            <version>0.9.0version>
        dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    编写token工具类

    package com.zs.jwt.util;
    
    import io.jsonwebtoken.Claims;
    import io.jsonwebtoken.JwtBuilder;
    import io.jsonwebtoken.Jwts;
    import io.jsonwebtoken.SignatureAlgorithm;
    
    import javax.crypto.SecretKey;
    import javax.crypto.spec.SecretKeySpec;
    import java.nio.charset.StandardCharsets;
    import java.util.Base64;
    import java.util.Date;
    import java.util.UUID;
    
    /**
     * JWT工具类
     */
    public class JJwtUtil {
    
        //有效期为
        public static final Long JWT_TTL = 60 * 60 *1000L;// 60 * 60 *1000  一个小时
    
        //设置秘钥明文
        public static final String JWT_KEY = "123456abc";
    
    
        public static String getUUID(){
            String token = UUID.randomUUID().toString().replaceAll("-", "");
            return token;
        }
    
        //对秘钥加密
        public static SecretKey generalKey() {
            //base64编码
            byte[] encodedKey = Base64.getEncoder().encode(JJwtUtil.JWT_KEY.getBytes(StandardCharsets.UTF_8));
            //AES秘钥类型
            return new SecretKeySpec(encodedKey,"AES");
        }
    
        public static void main(String[] args) throws Exception {
            String jwt = createJWT("{zs666}");
            System.out.println(jwt);
    
            Claims claims = parseJWT(jwt);
            System.out.println(claims);
        }
    
    
    
    
        /**
         * 生成jtw
         * @param subject token中要存放的数据(json格式)
         * @return
         */
        public static String createJWT(String subject) {
            JwtBuilder builder = getJwtBuilder(subject, null, getUUID());// 设置过期时间
            return builder.compact();
        }
        /**
         * 生成jtw
         * @param subject token中要存放的数据(json格式)
         * @param ttlMillis token超时时间
         * @return
         */
        public static String createJWT(String subject, Long ttlMillis) {
            JwtBuilder builder = getJwtBuilder(subject, ttlMillis, getUUID());// 设置过期时间
            return builder.compact();
        }
    
        /**
         * 创建token
         * @param id
         * @param subject
         * @param ttlMillis
         * @return
         */
        public static String createJWT(String id, String subject, Long ttlMillis) {
            JwtBuilder builder = getJwtBuilder(subject, ttlMillis, id);// 设置过期时间
            return builder.compact();
        }
    
    
        /**
         * 解析
         *
         * @param jwt
         * @return
         * @throws Exception
         */
        public static Claims parseJWT(String jwt) throws Exception {
            SecretKey secretKey = generalKey();
            return Jwts.parser()
                    .setSigningKey(secretKey)
                    .parseClaimsJws(jwt)
                    .getBody();
        }
    
    
    
        private static JwtBuilder getJwtBuilder(String subject, Long ttlMillis, String uuid) {
            if(ttlMillis==null){
                ttlMillis=JJwtUtil.JWT_TTL;
            }
            long nowMillis = System.currentTimeMillis();
            Date nowData = new Date(nowMillis);
            long expMillis = nowMillis + ttlMillis;
            Date expDate = new Date(expMillis);
    
            return Jwts.builder()
                    .setId(uuid)           //唯一的ID
                    .setSubject(subject)        // 主题  可以是JSON数据
                    .setIssuer("zs")            // 签发者
                    .setIssuedAt(nowData)       // 签发时间
                    .signWith(SignatureAlgorithm.HS256, generalKey()) //使用HS256对称加密算法签名, 第二个参数为秘钥
                    .setExpiration(expDate);    //过期时间
        }
    }
    
    • 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
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
  • 相关阅读:
    【iptables 实战】06 iptables网络防火墙实验
    FFmpeg学习总结
    史上最全阿里云盘资源搜索网站
    Dreamweaver网页设计与制作100例:用DIV+CSS技术设计的书法主题网站(web前端网页制作课作业)
    Java基础之浅谈继承、多态
    【PYTHON】中文分词库:jieba
    CF1168C And Reachability
    windows10 Docker Desktop中部署clickhouse
    学生dreamweaver网页设计作业成品___辅导网站( 4页 登录注册 轮播图)
    QT DAY4
  • 原文地址:https://blog.csdn.net/weixin_44235759/article/details/126790687