JWT学习笔记

了解 JWT Token 释义及使用 | Authing 文档

JSON Web Token Introduction - jwt.io

JSON Web Token (JWT,RFC 7519 (opens new window)),是为了在网络应用环境间传递声明而执行的一种基于 JSON 的开放标准((RFC 7519)。该 token 被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT 的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该 token 也可直接被用于认证,也可被加密。

1. 认证

传统的Session认证方式需要在服务器端存储用户登录信息,通常而言session都是保存在内存中,而随着认证用户的增多,服务端的开销会明显增大。基于Token的认证方式不需要在服务端去保留用户的认证信息或者会话信息。

流程上是这样的:

  • 用户使用用户名密码来请求服务器
  • 服务器进行验证用户的信息
  • 服务器通过验证发送给用户一个token
  • 客户端存储token,并在每次请求时附送上这个token值
  • 服务端验证token值,并返回数据

2. JWT的结构

它采用缩写的形式,包含三个部分,由.分割,包括以下三个部分

  • Header------头部
  • Payload------有效荷载
  • Signature------签名

因此JWT呈现为这种形式:

xxxxx.yyyyy.zzzzz

2.1. Header

头部包含两个部分:(1)token的类型,即JWT;(2)使用的签名算法,如HMAC、SHA256或RSA

例如:

{
  "alg": "HS256",
  "typ": "JWT"
}

2.2. Payload

该部分包含一些实体和数据的声明,如用户等,包括已注册声明、公开声明、私有声明三类。

例如:

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}

2.3. Signature

要创建签名部分,您必须获取编码的标头、编码的有效负载、密钥、标头中指定的算法,然后对其进行签名。

3. 使用

jjwt10:GitHub - jwtk/jjwt: Java JWT: JSON Web Token for Java and Android

目前jjwt10以上版本和jjwt9使用方法不同,好像使用jjwt9还是偏多一些。

jjwt9:jjwt 0.9.1 javadoc (io.jsonwebtoken)

以下代码是从mall项目中学习的JWT的工具类,一般可作为模板使用,主要提供了生成token和解析token的API,使用的是jjwt9

@Component
public class JwtTokenUtil {
    private static final Logger LOGGER = LoggerFactory.getLogger(JwtTokenUtil.class);

    //sub: subject,主体,即登录的主体,一般是用户名
    private static final String CLAIM_KEY_USERNAME = "sub";

    //created表示创建时间
    private static final String CLAIM_KEY_CREATED = "created";
    @Value("${jwt.secret}")
    private String secret;
    @Value("${jwt.expiration}")
    private Long expiration;

    /**
     * 根据负载生成JWT的token
     * @param claims 声明,即JWT中的payload部分
     * @return token:String
     */
    private String generateToken(Map<String, Object> claims) {
        return Jwts.builder()   //生成一个DefaultJwtBuilder类实例
                .setClaims(claims)      //设置该DefaultJwtBuilder类实例的claims字段
                .setExpiration(generateExpirationDate())    //设置过期时间
                .signWith(SignatureAlgorithm.HS512, secret) //设置签名算法、密钥
                .compact();     //调用compact函数才能生成JWT
    }

    /**
     * 从token中获取JWT中的负载
     * @param token
     * @return Claims类实例
     */
    private Claims getClaimsFromToken(String token) {
        Claims claims = null;
        try {
            claims = Jwts.parser()
                    .setSigningKey(secret)
                    .parseClaimsJws(token)
                    .getBody();
        } catch (Exception e) {
            LOGGER.info("JWT格式验证失败:{}",token);
        }
        return claims;
    }

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

    /**
     * 从token中获取登录用户名
     */
    public String getUserNameFromToken(String token) {
        String username;
        try {
            Claims claims = getClaimsFromToken(token);
            username =  claims.getSubject();
        } catch (Exception e) {
            username = null;
        }
        return username;
    }

    /**
     * 验证token是否还有效
     *
     * @param token       客户端传入的token
     * @param userDetails 从数据库中查询出来的用户信息
     */
    public boolean validateToken(String token, UserDetails userDetails) {
        String username = getUserNameFromToken(token);
        return username.equals(userDetails.getUsername()) && !isTokenExpired(token);
    }

    /**
     * 判断token是否已经失效
     */
    private boolean isTokenExpired(String token) {
        Date expiredDate = getExpiredDateFromToken(token);
        return expiredDate.before(new Date());
    }

    /**
     * 从token中获取过期时间
     */
    private Date getExpiredDateFromToken(String token) {
        Claims claims = getClaimsFromToken(token);
        return claims.getExpiration();
    }

    /**
     * 根据用户信息生成token
     * @param userDetails UserDetails类实例
     * @return token
     */
    public String generateToken(UserDetails userDetails) {
        Map<String, Object> claims = new HashMap<>();
        claims.put(CLAIM_KEY_USERNAME, userDetails.getUsername());
        claims.put(CLAIM_KEY_CREATED, new Date());
        return generateToken(claims);
    }
}
相关推荐
盛夏绽放15 天前
Node.js中JWT的token完整生命周期管理:从生成到销毁
后端·node.js·jwt
2的n次方_15 天前
如何通过 JWT 来解决登录认证问题
java·后端·spring·jwt
花姐夫Jun17 天前
node.js基础学习-JWT登录鉴权(十四)
学习·node.js·jwt·json web token
程楠楠&M19 天前
node.js实现分页,jwt鉴权机制,token,cookie和session的区别
前端·javascript·中间件·node.js·jwt·koa-jwt
布朗克16825 天前
JWT介绍和结合springboot项目实践(登录、注销授权认证管理)
java·spring boot·后端·安全·jwt
蜗牛丨1 个月前
Go Vue3 CMS管理后台(前后端分离模式)
mysql·docker·go·vue3·axios·gin·jwt·分页·跨域·ant design vue·log·gorm·otp动态码登录·validator·模型绑定·权限判断
kali-Myon1 个月前
ctfshow-web入门-JWT(web345-web350)
前端·学习·算法·web安全·node.js·web·jwt
NiNg_1_2341 个月前
Spring Boot 集成JWT实现Token验证详解
spring boot·后端·jwt·token
春天的菠菜2 个月前
【django】Django REST Framework (DRF) 项目中实现 JWT
后端·python·django·jwt
景天科技苑2 个月前
【Golang】Gin框架中如何使用JWT来实现登录认证
开发语言·golang·gin·jwt·登录认证·go jwt