zoukankan      html  css  js  c++  java
  • JWT 基础教程

    原文地址:JWT 基础教程
    博客地址:http://www.extlight.com

    一、前言

    针对前后端分离的项目,大多是通过 token 进行身份认证来进行交互,今天将介绍一种简单的创建 token 的方式 -- JWT。

    二、基本介绍

    2.1 定义

    JSON Web Token(JWT)是一个非常轻巧的规范。这个规范允许我们使用 JWT 在用户和服务器之间传递安全可靠的信息。

    2.2 组成部分

    一个 JWT 实际上就是一个字符串,它由三部分组成,头部、载荷与签名。前两部分需要经过 Base64 编码,后一部分通过前两部分 Base64 编码后再加密而成。

    如果读者不理解上边的陈述,不要紧,下文会详细讲解。

    头部(Header)

    头部用于描述关于该 JWT 的最基本的信息,例如其类型以及签名所用的算法等,也可以被表示成一个 JSON 对象。例如:

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

    在头部指明了签名算法是 HS256 算法。

    经过 Base64 编码得到:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9(第一部分)。下文参考资料提供线上加密/解密网址,感兴趣的读者可以自己尝试。

    载荷(playload)

    载荷就是存放有效信息的地方。这些有效信息包含三个部分:

    (1)标准中注册的声明(建议但不强制使用)

    iss: jwt签发者
    sub: jwt所面向的用户
    aud: 接收jwt的一方
    exp: jwt的过期时间,这个过期时间必须要大于签发时间
    nbf: 定义在什么时间之前,该jwt都是不可用的.
    iat: jwt的签发时间
    jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击
    

    (2)公共的声明

    公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息,但不建议添加敏感信息,因为该部分在客户端可解密。
    

    例如:

    {"id":"123456","name":"MoonlightL","sex":"male"}
    

    将该 json 字符串进行 Base64 编码得到:eyJpZCI6IjEyMzQ1NiIsIm5hbWUiOiJNb29ubGlnaHRMIiwic2V4IjoibWFsZSJ9(第二部分)。

    (3)私有的声明

    私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64 是对称解密的,意味着该部分信息可以归类为明文信息。
    

    注意:载荷中的这3个声明并不是都要同时设置。

    签证(signature)

    jwt的第三部分是一个签证信息。

    这个部分需要 Base64 加密后的 header 和 Base64 加密后的 payload 使用 “.” 连接组成的字符串,然后通过 header 中声明的加密方式进行加盐 secret 组合加密,然后就构成了 jwt 的第三部分。
    

    即将 eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6IjEyMzQ1NiIsIm5hbWUiOiJNb29ubGlnaHRMIiwic2V4IjoibWFsZSJ9 进行 HS256 算法加密(header 定义的)得到:

    e5dda3f17226c1c6ca7435cd17f83ec0c74d62bd8e8386e1a178cd970737f09f(第三部分)。

    最后,我们将上述的 3 个部分的字符串通过 “.” 进行拼接得到 JWT:

    eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6IjEyMzQ1NiIsIm5hbWUiOiJNb29ubGlnaHRMIiwic2V4IjoibWFsZSJ9.e5dda3f17226c1c6ca7435cd17f83ec0c74d62bd8e8386e1a178cd970737f09f

    为了验证上述生成的 jwt 是否合法,我们可以登录 JWT 官网,官网界面提供 JWT 解密功能,将生成好的 JWT 复制到如下图中进行解密:

    image

    在实际开发中,用户登录成功后,后端生成 jwt 返回给前端,之后,前端与后端交互时携带 jwt 让后端验证 jwt 的合法性。

    三、实战入门

    通过上述的介绍,我们已经了解到什么是 JWT 以及 JWT 生成的规则,现在我们通过代码方式来生成 JWT。

    JWT 官网提供了通过不同编程语言来创建 JWT 的工具类/库,此次测试我们选用 JJWT 。

    3.1 添加依赖

    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt-api</artifactId>
        <version>0.10.5</version>
    </dependency>
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt-impl</artifactId>
        <version>0.10.5</version>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt-jackson</artifactId>
        <version>0.10.5</version>
        <scope>runtime</scope>
    </dependency>
    

    3.2 编码

    import java.security.Key;
    import java.util.Date;
    import java.util.UUID;
    import org.junit.Test;
    import io.jsonwebtoken.Claims;
    import io.jsonwebtoken.Jws;
    import io.jsonwebtoken.JwtBuilder;
    import io.jsonwebtoken.JwtException;
    import io.jsonwebtoken.Jwts;
    import io.jsonwebtoken.SignatureAlgorithm;
    import io.jsonwebtoken.security.Keys;
    
    public class JWTTest {
    
    	@Test
    	public void testJWT() {
    		
    		Key key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
    		
    		System.out.println("=============创建 JWT===========");
    		Date now = new Date();
    		JwtBuilder builder= Jwts.builder()
    				                .setId(UUID.randomUUID().toString()) // 载荷-标准中注册的声明
    				                .setSubject("admin") // 载荷-标准中注册的声明
    				                .setIssuedAt(now) // 载荷-标准中注册的声明,表示签发时间
    				                .claim("id", "123456") // 载荷-公共的声明
    				                .claim("name", "MoonlightL") // 载荷-公共的声明
    				                .claim("sex", "male") // 载荷-公共的声明
    								.signWith(key); // 签证
    		
    		String jwt = builder.compact();
    		System.out.println("生成的 jwt :" +jwt);
    		
    		System.out.println("=============解析 JWT===========");
    		
    		try {
    			Jws<Claims> result = Jwts.parser().setSigningKey(key).parseClaimsJws(jwt);
    			// 以下步骤随实际情况而定,只要上一行代码执行不抛异常就证明 jwt 是有效的、合法的
    			Claims body = result.getBody();
    			
    			System.out.println("载荷-标准中注册的声明 id:" + body.getId());
    			System.out.println("载荷-标准中注册的声明 subject:" + body.getSubject());
    			System.out.println("载荷-标准中注册的声明 issueAt:" + body.getIssuedAt());
    			
    			
    			System.out.println("载荷-公共的声明的 id:" + result.getBody().get("id"));
    			System.out.println("载荷-公共的声明的 name:" + result.getBody().get("name"));
    			System.out.println("载荷-公共的声明的 sex:" + result.getBody().get("sex"));
    			
    		} catch (JwtException ex) { // jwt 不合法或过期都会抛异常      
    		    ex.printStackTrace();
    		}
    	}
    }
    

    执行结果:

    =============创建 JWT===========
    生成的 jwt :eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI3ZjZmZjRlMC04YjM5LTQyYjUtOGRkNS0xN2M4ZjM5ZmZhNzMiLCJzdWIiOiJhZG1pbiIsImlhdCI6MTU0MzIwNTI4OSwiZXhwIjoxNTQzMjA1MzQ5LCJpZCI6IjEyMzQ1NiIsIm5hbWUiOiJNb29ubGlnaHRMIiwic2V4IjoibWFsZSJ9.BtEi-GCj5mCunXD_g0Cra7CSE_bMxhTzlOELWKc17I8
    =============解析 JWT===========
    载荷-标准中注册的声明 id:7f6ff4e0-8b39-42b5-8dd5-17c8f39ffa73
    载荷-标准中注册的声明 subject:admin
    载荷-标准中注册的声明 issueAt:Mon Nov 26 12:08:09 CST 2018
    载荷-公共的声明的 id:123456
    载荷-公共的声明的 name:MoonlightL
    载荷-公共的声明的 sex:male
    

    注意:加密和解密 JWT 必须是同一个 Key 对象

    注意:解密 JWT 时,必须要抓取 JwtException 异常,只要抓取到该异常说明该 JWT 不可用了

    JJWT 库还有其他使用方式,具体资料请查看下边提供的参考资料。

    四、参考资料

    JWT 官网

    JJWT 官网

    JSON Web Token 入门教程

    在线工具

  • 相关阅读:
    uni-app 版本更新控制
    Chrome为什么打开一个页面,会有4个进程?
    vue 导航栏滚动吸顶
    vue 运行后, sass 报错
    HAProxy——HAProxy、Nginx、LVS优势劣势 (转)
    HAProxy——关于配置的备份
    RabbitMQ——用HAProxy实现负载均衡
    docker——Docker常见问题总结 (转)
    docker——docker容器内存和CPU使用限制
    docker——用docker-compose安装redis
  • 原文地址:https://www.cnblogs.com/moonlightL/p/10020732.html
Copyright © 2011-2022 走看看