JWT(1)简介和基础示例

JWT
placeholder image
admin 发布于:2023-01-29 17:37:49
阅读:loading

基础知识

JSON Web Token(JWT)是一种开放标准(RFC 7519),它定义了一种紧凑且自包含的方式,用于在各方之间作为JSON对象安全地传输信息。此信息可以验证和信任,因为它是数字签名的。JWT可以使用秘密(使用HMAC算法)或使用RSA或ECDSA的公钥/私钥对签名。简单来说,JWT就是通过 JSON 形式作为 Web 应用中的令牌,用于在各方之间安全地将信息作为 JSON 对象传输,这个令牌Token,是一串字符串,三部分组成:标头(Header)、有效载荷(Payload)、签名(Signature),它的数据被分为以“.”分割的三段文本,格式如:xxx.yyy.zzz,其中xxx和yyy是使用Base64编码的文本,可将这两部分的数据直接采用Base64解码得到原始的文本数据,所以在这两段的文本中xxx是定义当前的Token加密方式;yyy部分是存储Token解码后的数据,如用户id、用户名称、用户头像等非敏感数据;而zzz部分是对前面两段文本进行加密后的签名,在签名时可使用对称加密或非对称加密等多种加密手段进行保护数据,所以只要Token中前两段文本发生变化后zzz部分的签名是无法验证通过的。

JWT在行业技术讨论中是极具争议性的存在,争议的焦点在于JWT非常轻量级好使用,以至于若被应用于不合理的场景下就成了累赘,导致使用它反而成了得不偿失的结果或者成为重量枷锁的应用。我的意见是充分掌握它,站在一定的高度并且结合实际业务应用场景进行选择使用,技术知识就当站在技术的焦点纯粹学习即可。JWT最大的几个特点:

(1)无状态,服务端不存储,完全由客户端自行存储,待提交请求时由服务端进行可用性校验;正是由于服务端不存储可以降低服务端的压力的,但也导致了它的不可控性,比如无法立即销毁一个Token,或者无法给一个Token续期;

(2)安全性,加密Token传递参数,不使用Cookie更符合移动端应用或Api接口传输,有效避免CSRF 攻击;

(3)单点登录友好,可直接跨服务共享用户数据,无需服务端使用会话跟踪技术;

(4)轻量级,服务端可以简单到一个工具类验证的程度;

简单示例

package cn.chendd.jjwt;

import ...;

/**
 * Jjwt的基本应用测试实践
 *
 * @author chendd
 * @date 2022/10/22 22:03
 */
@RunWith(JUnit4.class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class JjwtHelloTest {

    String jwtTokenHello;

    @Before
    public void generateToken() {
        this.jwtTokenHello = Jwts.builder().setPayload("Hello Wolrd").compact();
    }

    @Test
    public void hello() {
        System.out.println("默认无加密的token签名:" + this.jwtTokenHello);
    }

    @Test
    public void helloParse() {
        System.out.println("解析无加密的token签名:" + Jwts.parserBuilder().build().parse(this.jwtTokenHello));
    }


}

image.png

基础示例

package cn.chendd.jjwt;

import ...;

/**
 * Jjwt基本使用测试,
 *
 * @author chendd
 * @date 2022/10/23 10:03
 */
@RunWith(JUnit4.class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class JjwtBasicTest {

    private static String JWT_TOKEN;
    private static SecretKey KEY = Keys.secretKeyFor(SignatureAlgorithm.HS256);

    @Test
    public void generateToken() {
        long current = System.currentTimeMillis();
        JWT_TOKEN = Jwts.builder()
                //设置 header 部分头信息
                .setHeaderParam(JwsHeader.TYPE, JwsHeader.JWT_TYPE)
                .setHeaderParam(JwsHeader.ALGORITHM, SignatureAlgorithm.HS256.getValue())
                //设置 payload 部分有效载荷信息(标准的Token属性)
                .setClaims(new DefaultClaims()
                        //唯一身份标识,用于生成一次性Token,避免重放攻击
                        .setId(UUID.randomUUID().toString())
                        //设置Token主题
                        .setSubject("chendd-jwt-example")
                        //过期时间,指定从现在开始到什么时候过期
                        .setExpiration(new Date(current + 1000 * 60 * 60 * 12))
                        //设置Token签发者
                        .setIssuer("chendd")
                        //设置Token签发时间
                        .setIssuedAt(new Date(current))
                        //设置Token开始可用时间
                        .setNotBefore(new Date(current))
                        //设置Token接收方
                        .setAudience("example")
                )
                //设置加密信息
                .signWith(KEY)
                .compact();
        System.out.println("生成JwtToken:" + JWT_TOKEN);
    }

    @Test
    public void validatorToken() {
        //默认解析
        Jwt jwt = Jwts.parserBuilder().setSigningKey(KEY).build().parse(JWT_TOKEN);
        Header header = jwt.getHeader();
        System.out.println("解析JwtToken Header:" + header);
        DefaultClaims payload = (DefaultClaims) jwt.getBody();
        System.out.println("解析JwtToken Payload:" + payload);
        //可以拿到签名参数
        Jws<Claims> claimsJws = Jwts.parserBuilder().setSigningKey(KEY).build().parseClaimsJws(JWT_TOKEN);
        System.out.println(claimsJws);
    }

}

image.png

源码下载

源码见“源码下载.zip


 点赞


 发表评论

当前回复:作者

 评论列表


留言区