Jwt

Jwt

JWT是JSON WEB TOKEN的缩写,它是基于 RFC 7519 标准定义的一种可以安全传输的的JSON对象,由于使用了数字签名,所以是可信任和安全的。

组成

header.payload.signature

header中存放签名的生成算法

payload存放附加信息

signature为通过header和payload生成的签名

原理

用户登录后,系统生成token返回给用户。

之后每次调用接口都要在请求中添加Authorization请求头,值为之前的token。

后台系统通过token来对用户认证和授权

jwt不能防止冒充其他用户

使用

  1. 导入坐标

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.0</version>
    </dependency>
    <!-- 用到SpringSecurity来传用户信息 -->
    <!--SpringSecurity依赖配置-->
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
  2. 添加配置

    1
    2
    3
    4
    5
    6
    # 自定义jwt key
    jwt:
    tokenHeader: Authorization #JWT存储的请求头
    secret: mySecret #JWT加解密使用的密钥
    expiration: 604800 #JWT的超期限时间(60*60*24)
    tokenHead: Bearer #JWT负载中拿到开头
  3. 编写工具类(结合Spring Security)

    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
    package com.xw.mallLearning.utils;

    import io.jsonwebtoken.*;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.security.core.userdetails.UserDetails;
    import org.springframework.stereotype.Component;

    import java.util.Date;
    import java.util.HashMap;
    import java.util.Map;

    /**
    * token工具类
    * 获取token、校验token、刷新token过期时间
    */
    @Slf4j
    @Component
    public class JwtTokenUtil {

    private static final String CLAIM_KEY_USERNAME = "sub";
    private static final String CLAIM_KEY_CREATED = "created";

    @Value("${jwt.secret}")
    private String secret; // 加密秘钥
    @Value("${jwt.expiration}")
    private Long expiration; // token保留时间

    // 获取token中的用户名
    public String getUserNameFormToken(String token) {
    String username;
    try {
    Claims claims = getClaimsFormToken(token);
    username = claims.getSubject();
    } catch (Exception e) {
    return null;
    }
    return username;
    }

    // 验证token是否有效
    public boolean validateToken(String token, UserDetails userDetails) {
    String username = getUserNameFormToken(token);
    return userDetails.getUsername().equals(username) && isTokenExpired(token);
    }

    // 生成Token
    public String generateToken(UserDetails userDetails) {
    HashMap<String, Object> claims = new HashMap<>();
    claims.put(CLAIM_KEY_USERNAME, userDetails.getUsername());
    claims.put(CLAIM_KEY_CREATED, new Date());
    return generateTokenFromClaims(claims);
    }

    // 刷新token
    public String refreshToken(String token) {
    Claims claims = getClaimsFormToken(token);
    claims.put(CLAIM_KEY_CREATED, new Date());
    return generateTokenFromClaims(claims);
    }

    // 验证token是否实效
    private boolean isTokenExpired(String token) {
    Date expireDate = getExpireDateFormToken(token);
    return expireDate.before(new Date());
    }

    // 获取Token过期时间
    private Date getExpireDateFormToken(String token) {
    Claims claims = getClaimsFormToken(token);
    return claims.getExpiration();
    }

    // 根据负载信息生成Token
    private String generateTokenFromClaims(Map<String, Object> claims) {
    return Jwts.builder()
    .setClaims(claims) // 设置token中负载信息
    .setExpiration(generateExpirationDate()) // 设置超时时间
    .signWith(SignatureAlgorithm.ES512, secret) // 设置加密方式
    .compact();
    }

    // 生成Token过期时间
    private Date generateExpirationDate() {
    return new Date(System.currentTimeMillis() + expiration * 1000);
    }

    // 获取token中的JWT负载
    private Claims getClaimsFormToken(String token) {
    Claims claims = null;
    try {
    claims = Jwts.parser()
    .setSigningKey(secret)
    .parseClaimsJws(token)
    .getBody();
    } catch (Exception e) {
    log.info("JWT验证失败:{}", token);
    }
    return claims;
    }
    }

  4. 编写工具类(不是用其他框架)

    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
    119
    120
    121
    122
    123
    124
    125
    package com.xw.place.utils;

    import io.jsonwebtoken.*;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Component;

    import javax.crypto.SecretKey;
    import javax.crypto.spec.SecretKeySpec;
    import java.util.Base64;
    import java.util.Date;
    import java.util.HashMap;
    import java.util.UUID;

    /**
    * token工具类
    * 获取token、校验token、刷新token过期时间
    */
    @Slf4j
    @Component
    public class JwtTokenUtil {
    @Value("${jwt.secret}")
    private static String SECRET; // 加密秘钥

    @Value("${jwt.expiration}")
    private static Long EXPIRATION; // token保留时间(s)

    @Value("${jwt.refresh_time}")
    private static Integer REFRESH_TIME;

    /**
    * 生成token
    * @param id
    * @return
    */
    public static String getToken(Long id) {
    HashMap<String, Object> claimMaps = new HashMap<>();
    claimMaps.put("id", id);
    long currentTime = System.currentTimeMillis();
    return Jwts.builder()
    .setId(UUID.randomUUID().toString())
    .setIssuedAt(new Date(currentTime)) // 签发时间
    .setSubject("system") // 说明
    .setAudience("app") // 接收用户
    .compressWith(CompressionCodecs.GZIP) // 数据压缩方式
    .signWith(SignatureAlgorithm.HS512, generalKey()) // 数据压缩方式
    .setExpiration(new Date(currentTime + EXPIRATION * 1000)) // 过期时间戳
    .addClaims(claimMaps) // 载荷信息
    .compact();
    }

    /**
    * 生成加密key
    * @return
    */
    public static SecretKey generalKey() {
    byte[] encodedKey = Base64.getEncoder().encode(SECRET.getBytes());
    SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
    return key;
    }

    /**
    * 获取payload body信息
    *
    * @param token
    * @return
    */
    public static Claims getClaimsBody(String token) {
    try {
    return getJws(token).getBody();
    } catch (Exception e) {
    return null;
    }
    }

    /**
    * 获取headers body信息
    * @param token
    * @return
    */
    public static JwsHeader getHeaderBody(String token) {
    return getJws(token).getHeader();
    }

    /**
    * 判断token是否过期
    * @param claims
    * @return -1 有效,0 有效,1:过期,2 过期
    */
    public static int verifyToken(Claims claims) {
    if (claims == null) {
    return 1;
    }
    try {
    claims.getExpiration()
    .before(new Date());
    if ((claims.getExpiration().getTime() - System.currentTimeMillis()) > REFRESH_TIME * 1000) {
    return -1;
    } else {
    return 0;
    }
    } catch (ExpiredJwtException ex) {
    return 1;
    } catch (Exception e) {
    return 2;
    }
    }

    // 获取载荷信息
    private static Jws<Claims> getJws(String token) {
    return Jwts.parser()
    .setSigningKey(generalKey())
    .parseClaimsJws(token);
    }


    // 测试
    public static void main(String[] args) {
    System.out.println(JwtTokenUtil.getToken(1102L));
    Jws<Claims> jws = JwtTokenUtil.getJws("eyJhbGciOiJIUzUxMiIsInppcCI6IkdaSVAifQ.H4sIAAAAAAAAAB2LUQrEIAwF75JvBROjYm-jVcGFBUELW0rv3nT_3jDzLvisDhtwKxzCbrRr6DQ3izqVitpzzL5FyqYgKOhpwYY-UkDHziuYR5b3POeqX_HpKIJpDNn1N_6ttWTobbs4REP3Az_PtEl1AAAA.Mrst1ZCLW7ItSxLl26TiYbpN-7XPNn1HUuP0ZyGqNZgLitUlt3Vqfnu9MGI1blugwdI6wBriAmydZITaYuRRmA");
    Claims claims = jws.getBody();
    System.out.println(claims.get("id"));
    }
    }


Jwt
http://xwww12.github.io/2023/02/06/其他/Jwt/
作者
xw
发布于
2023年2月6日
许可协议