• JWT 登录


    token认证

    随着 Restful API、微服务的兴起,基于 token 的认证现在已经越来越普遍。基于token的用户认证是一种服务端无状态的认证方式,所谓服务端无状态指的token本身包含登录用户所有的相关数据,而客户端在认证后的每次请求都会携带token,因此服务器端无需存放token数据。

    ​ 当用户认证后,服务端生成一个token发给客户端,客户端可以放到 cookie 或 localStorage 等存储中,每次请求时带上 token,服务端收到token通过验证后即可确认用户身份。

    在这里插入图片描述

    什么是JWT

    ​ 我们现在了解了基于token认证的交互机制,但令牌里面究竟是什么内容?什么格式呢?市面上基于token的认证方式大都采用的是JWT(Json Web Token)。

    ​ JSON Web Token(JWT)是一个开放的行业标准(RFC 7519),它定义了一种简洁的、自包含的协议格式,用于在通信双方传递json对象,传递的信息经过数字签名可以被验证和信任。

    JWT令牌结构:

    JWT令牌由Header、Payload、Signature三部分组成,每部分中间使用点(.)分隔,比如:xxxxx.yyyyy.zzzzz

    • Header

    头部包括令牌的类型(即JWT)及使用的哈希算法(如HMAC、SHA256或RSA)。

    一个例子:

    {
    	"alg": "HS256""typ": "JWT"
    }
    
    • 1
    • 2
    • 3
    • 4

    将上边的内容使用Base64编码,得到一个字符串就是JWT令牌的第一部分。

    • Payload

    第二部分是负载,内容也是一个json对象,它是存放有效信息的地方,它可以存放jwt提供的现成字段,比
    如:iss(签发者),exp(过期时间戳), sub(面向的用户)等,也可自定义字段。
    此部分不建议存放敏感信息,因为此部分可以解码还原原始内容。
    一个例子:

    {
    	"sub": "1234567890""name": "456""admin": true
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    最后将第二部分负载使用Base64编码,得到一个字符串就是JWT令牌的第二部分。

    • Signature

    第三部分是签名,此部分用于防止jwt内容被篡改。
    这个部分使用base64将前两部分进行编码,编码后使用点(.)连接组成字符串,最后使用header中声明
    签名算法进行签名。
    一个例子:

    HMACSHA256(  base64UrlEncode(header) + "." +  base64UrlEncode(payload),secret)
    
    • 1

    使用jwt生成token

    1. 引入依赖
    <dependency>
        <groupId>io.jsonwebtokengroupId>
        <artifactId>jjwtartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    1. 封装jjwt的的工具类
    import com.heima.common.dtos.Payload;
    import io.jsonwebtoken.*;
    import org.joda.time.DateTime;
    import javax.crypto.SecretKey;
    import javax.crypto.spec.SecretKeySpec;
    import java.util.*;
    
    /**
     * JWT 工具类
     * 对JJWT的封装
     */
    public class JwtUtils {
    
        private static final String JWT_PAYLOAD_USER_KEY = "id";
        // 加密KEY
        private static final String TOKEN_ENCRY_KEY = "MDk4ZjZiY2Q0NjIxZDM3M2NhZGU0ZTgzMjYyN2I0ZjY";
    
        /**
         * 加密token
         *
         * @param userId 载荷中的数据
         * @param expire 过期时间,单位分钟
         * @return JWT
         */
        public static String generateTokenExpireInMinutes(Integer userId, int expire) {
            Map<String, Object> claimMaps = new HashMap<>();
            claimMaps.put(JWT_PAYLOAD_USER_KEY,userId);
            return Jwts.builder()
                    .addClaims(claimMaps)
                    .setId(createJTI())
                    .setExpiration(DateTime.now().plusMinutes(expire).toDate())
                    .compressWith(CompressionCodecs.GZIP)  //数据压缩方式
                    .setIssuedAt(new Date(System.currentTimeMillis()))  //签发时间
                    .setSubject("system")  //说明
                    .setIssuer("heima") //签发者信息
                    .setAudience("app")  //接收用户
                    .signWith(SignatureAlgorithm.HS256, generalKey())
                    .compact();
        }
    
        /**
         * 由字符串生成加密key
         *
         * @return
         */
        public static SecretKey generalKey() {
            byte[] encodedKey = Base64.getEncoder().encode(TOKEN_ENCRY_KEY.getBytes());
            SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
            return key;
        }
    
        /**
         * 加密token
         *
         * @param userId 载荷中的数据
         * @param expire 过期时间,单位秒
         * @return JWT
         */
        public static String generateTokenExpireInSeconds(Integer userId, int expire) {
            Map<String, Object> claimMaps = new HashMap<>();
            claimMaps.put(JWT_PAYLOAD_USER_KEY,userId);
            return Jwts.builder()
                    .addClaims(claimMaps)
                    .setId(createJTI())
                    .setExpiration(DateTime.now().plusSeconds(expire).toDate())
                    .compressWith(CompressionCodecs.GZIP)  //数据压缩方式
                    .setIssuedAt(new Date(System.currentTimeMillis()))  //签发时间
                    .setSubject("system")  //说明
                    .setIssuer("heima") //签发者信息
                    .setAudience("app")  //接收用户
                    .signWith(SignatureAlgorithm.HS256, generalKey())
                    .compact();
        }
    
        /**
         * 解析token
         *
         * @param token 用户请求中的token
         * @return Jws
         */
        private static Jws<Claims> parserToken(String token) {
            return Jwts.parser().setSigningKey(generalKey()).parseClaimsJws(token);
        }
    
        private static String createJTI() {
            return new String(Base64.getEncoder().encode(UUID.randomUUID().toString().getBytes()));
        }
    
        /**
         * 获取token中的用户信息
         *
         * @param token 用户请求中的令牌
         * @return 用户信息
         */
        public static Payload getInfoFromToken(String token) {
            Jws<Claims> claimsJws = parserToken(token);
            Claims body = claimsJws.getBody();
            Payload claims = new Payload();
            claims.setId(body.getId());
            claims.setUserId(Integer.valueOf(body.get(JWT_PAYLOAD_USER_KEY).toString()));
            claims.setExpiration(body.getExpiration());
            return 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
    1. 生成token,解析token
        public static void main(String[] args) {
            //生成token
            String token = JwtUtils.generateTokenExpireInMinutes(209617, 30);
            System.out.println("生成的token:\n" + token);
    
            //解析token
            try {
                Payload payload = JwtUtils.getInfoFromToken(token);
                System.out.println("解析后的payload内容为:\n" + payload);
            } catch (Exception e) {
                System.out.println("解析token失败");
                e.printStackTrace();
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
  • 相关阅读:
    python开篇——初识python
    【PCL】NDT点云配准(Registration)
    Git 如何合并commits成一个(squash)
    HDFS的读写流程——宏观与微观
    基于链表的滑动中值滤波器实现思路
    Biome-BGC生态系统模型与Python融合技术实践应用
    小程序 swiper滑动 层叠滑动效果
    数据治理资料整理合集
    深度理解Synchronized及底层原理
    【Java面试】工作7年去字节面试竟然在这题翻车了,请你说一下你对时间轮的理解?
  • 原文地址:https://blog.csdn.net/ZHHX666/article/details/127448550