JWT生成令牌

实现步骤

  1. 引入JWT包
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.12.3</version>
</dependency>
  1. 定义令牌类型枚举
package com.angel.ocean.token.constant;

public enum TokenTypeEnum {

    ACCESS_TOKEN(0),
    REFRESH_TOKEN(1);

    private int code;
    TokenTypeEnum(int code) {
        this.code = code;
    }
    public int getCode() {
        return code;
    }
}
  1. 定义令牌数据模型

令牌信息类 TokenInfo

package com.angel.ocean.token.model;

import lombok.Data;

@Data
public class TokenInfo {
    /**
     * 令牌
     */
    private String accessToken;
    /**
     * 令牌过期时间,秒级时间戳
     */
    private Long accessTokenExpireIn;
    /**
     * 刷新令牌
     */
    private String refreshToken;

    /**
     * 刷新令牌过期时间,秒级时间戳
     */
    private Long refreshTokenExpireIn;

}

用户信息类 UserInfo

package com.angel.ocean.token.model;

import lombok.Data;

/**
 * 用户信息
 */
@Data
public class UserInfo {

    private Long uid;

    private String name;

}
  1. 定义生成令牌的工具类

主要包含以下功能:

  • 生成令牌
  • 刷新令牌
  • 获取令牌用户数据
  • 令牌过期校验
package com.angel.ocean.token;

import com.angel.ocean.token.constant.TokenTypeEnum;
import com.angel.ocean.token.model.TokenInfo;
import com.angel.ocean.token.model.UserInfo;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.JwsHeader;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import io.jsonwebtoken.security.SecureDigestAlgorithm;
import javax.crypto.SecretKey;
import java.time.Instant;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

public class TokenUtil {

    /**
     * 过期时间(单位:秒)
     */
    public static final Integer ACCESS_TOKEN_EXPIRE = 300;

    /**
     * 过期时间(单位:秒)
     */
    public static final Integer REFRESH_TOKEN_EXPIRE = 7200;

    /**
     * 加密算法
     */
    private final static SecureDigestAlgorithm<SecretKey, SecretKey> ALGORITHM = Jwts.SIG.HS256;

    /**
     * 私钥
     */
    private final static String SECRET = "lMN0So4pxpeyPec3ap32Vg7e6JkjEjfT";

    /**
     * 秘钥实例
     */
    public static final SecretKey KEY = Keys.hmacShaKeyFor(SECRET.getBytes());

    /**
     * jwt签发者
     */
    private final static String JWT_ISS = "Ocean";

    /**
     * jwt主题
     */
    private final static String SUBJECT = "Peripherals";

    /**
     * 生成令牌
     * @param userInfo
     * @return
     */
    public static TokenInfo generateToken(UserInfo userInfo) {

        Map<String, Object> payload = new HashMap<>();

        payload.put("name", userInfo.getName());
        payload.put("uid", userInfo.getUid());

        payload.put("type", TokenTypeEnum.ACCESS_TOKEN.getCode());
        Integer accessTokenExpireIn = ACCESS_TOKEN_EXPIRE;
        String accessToken = generateToken(payload, accessTokenExpireIn);


        payload.put("type", TokenTypeEnum.REFRESH_TOKEN.getCode());
        Integer refreshTokenExpireIn = REFRESH_TOKEN_EXPIRE;
        String refreshToken = generateToken(payload, refreshTokenExpireIn);

        TokenInfo tokenInfo = new TokenInfo();
        tokenInfo.setAccessToken(accessToken);
        tokenInfo.setAccessTokenExpireIn(getTokenExpireIn(accessToken));
        tokenInfo.setRefreshToken(refreshToken);
        tokenInfo.setRefreshTokenExpireIn(getTokenExpireIn(refreshToken));

        return tokenInfo;
    }

    /**
     * 刷新令牌
     * @param refreshToken
     * @return
     */
    public static TokenInfo refreshToken(String refreshToken) {
        UserInfo userInfo = getUserInfoByToken(refreshToken);
        return generateToken(userInfo);
    }

    /**
     * 获取令牌用户数据
     * @param token
     * @return
     */
    public static UserInfo getUserInfoByToken(String token) {
        final Claims claims = parsePayload(token);
        UserInfo userInfo = null;
        if (null != claims) {
            userInfo = new UserInfo();
            userInfo.setName(claims.get("name").toString());
            userInfo.setUid(Long.parseLong(claims.get("uid").toString()));
        }

        return userInfo;
    }

    /**
     * 令牌过期校验 true-过期 false-未过期
     * @param token
     * @return
     */
    public static Boolean isExpired(String token) {
        Boolean result = true;
        final Claims claims = parsePayload(token);
        if (null != claims) {
            String exp = claims.get("exp").toString();
            long diff = Long.parseLong(exp) - System.currentTimeMillis() / 1000;
            if(diff > 0) {
                result = false;
            }
        }

        return result;
    }

    /**
     * 获取令牌的过期时间
     */
    private static Long getTokenExpireIn(String token) {
        Long expireIn = System.currentTimeMillis() / 1000;
        final Claims claims = parsePayload(token);
        if (null != claims) {
            String exp = claims.get("exp").toString();
            return Long.parseLong(exp);
        }
        return expireIn;
    }


    /**
     * 生成令牌
     */
    private static String generateToken(Map<String, Object> payload, Integer expireTime) {

        Date expireDate = Date.from(Instant.now().plusSeconds(expireTime));

        return Jwts.builder()
                .header().add("typ", "JWT").add("alg", "HS256")
                .and()
                .claims(payload)
                .id(UUID.randomUUID().toString())
                .expiration(expireDate)
                .issuedAt(new Date())
                .subject(SUBJECT)
                .issuer(JWT_ISS)
                .signWith(KEY, ALGORITHM)
                .compact();
    }

    /**
     * 解析令牌claims
     */
    private static Jws<Claims> parseClaim(String token) {

        Jws<Claims> claimsJws = null;
        try {
            claimsJws = Jwts.parser() .verifyWith(KEY) .build().parseSignedClaims(token);
        } catch (JwtException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        }

        return claimsJws;
    }

    /**
     * 解析令牌header
     */
    private static JwsHeader parseHeader(String token) {
        Jws<Claims> claimsJws = parseClaim(token);
        if(null == claimsJws) {
            return null;
        }
        return claimsJws.getHeader();
    }

    /**
     * 解析令牌payload
     */
    private static Claims parsePayload(String token) {
        Jws<Claims> claimsJws = parseClaim(token);
        if(null == claimsJws) {
            return null;
        }
        return claimsJws.getPayload();
    }
}

生成令牌样式

{
    "accessToken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1aWQiOjEsIm5hbWUiOiJKYWltZSIsInR5cGUiOjAsImp0aSI6IjNjOWFhMDIxLWNkN2MtNDQ1Ni1hMTE1LTYxOWJkOTg3NzI2NCIsImV4cCI6MTcxOTA2MTQwMiwiaWF0IjoxNzE5MDYxMTAyLCJzdWIiOiJQZXJpcGhlcmFscyIsImlzcyI6Ik9jZWFuIn0.Cj_UJfbaWaiSu82ma-C1hd8L1u2_x3RRBHkXK5XFAPA",
    "accessTokenExpireIn": 1719061402,
    "refreshToken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1aWQiOjEsIm5hbWUiOiJKYWltZSIsInR5cGUiOjEsImp0aSI6IjU4YTVmZDAzLTlkYWYtNDY2ZS05NjMwLTQyNjU5ODZmYTViNiIsImV4cCI6MTcxOTA2ODMwMywiaWF0IjoxNzE5MDYxMTAzLCJzdWIiOiJQZXJpcGhlcmFscyIsImlzcyI6Ik9jZWFuIn0.jegxFBj4t-AJhiWY_OByEs0vtsHBb0d0vjEerVFl85E",
    "refreshTokenExpireIn": 1719068303
}

系统认证流程

  • 用户登录系统,用户有效,生成令牌返回给客户端(Web前端或APP等);
  • 客户端记录令牌信息和刷新令牌信息;
  • 客户端携带令牌(一般放在头信息中)去请求服务器的资源;
  • 服务进行令牌校验,检验通过返回资源信息给客户端,检验失败返回401(鉴权失败)给客户端;
  • 客户端收到401响应码,知道令牌失效了,此时使用刷新令牌去重新获取令牌;
  • 服务校验刷新令牌是否有效,如何有效,重新返回令牌信息给客户端(包含令牌和刷新令牌);
  • 如果刷新令牌校验失败,则返回402(刷新令牌校验失败),此时客户端需要跳转到登录页,用户需要重新登录。

系统认证基本流程可以参考下一节。

  • 6
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值