jwt-auth初识

已经被证实,下面的内容注水比较多,如有不适,请及时前往官网(https://jwt.io/)了解
JWT (JSON Web Token) 由三部分组成,每部分之间用点(.)分隔。这三部分分别是:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

  • 头部(Header)包含令牌的类型(即JWT)以及所使用的签名算法(如HMAC SHA256或者RSA)。eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
  • 载荷(Payload)包含声明,即关于实体的信息和其他数据。声明可以是注册声明(预定义的声明,如iss(发行者)、exp(过期时间)、sub(主题)等)、公共声明、私有声明。eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
  • 签名(Signature)用于验证消息在此过程中没有被更改,并且,对于带有过期时间的令牌,也可以确认发送者的身份。签名是通过对头部和载荷进行Base64Url编码后的字符串,连同密钥一起使用指定的算法计算得出。SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

1. 头部(Header)

头部通常包含两部分信息:令牌的类型(即JWT)和所使用的签名算法(如HMAC SHA256或者RSA)。例如:

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

2. 载荷(Payload)

载荷包含了声明(claims),即您想要传达的信息。声明分为三种类型:注册声明(registered claims)、公共声明(public claims)和私有声明(private claims)。例如:

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

3. 签名(Signature)

签名是用来验证消息在传输过程中没有被更改,并且,对于某些算法,还可以验证发送者的身份。签名是通过编码后的头部和载荷以及一个秘钥或私钥生成的。根据不同的加密方式,签名的生成方法也不同。

使用加密的方式多种样,包括使用 JJWT,Nimbus JOSE+JWT,Auth0 Java JWT等,万变不离其宗,所以记住定义以及各个部分比较重要。
这里使用Auth0 Java JWT实现:

依赖

        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>4.2.1</version> <!-- 请检查是否有更新版本 -->
        </dependency>

代码


    @Test
    void contextLoads() {

        try {
            // 创建一个带有签名算法的JWT
            String token = createToken();
            System.out.println("Generated JWT: " + token);

            // 验证并解析JWT
            DecodedJWT jwt = verifyToken(token);

            System.out.println("Decoded JWT: " + jwt.getToken());
            // 注册声明(registered claims)
            System.out.println(jwt.getSubject());
            // 公共声明(public claims)
            System.out.println(jwt.getIssuer());
            // 私有声明(private claims)
            System.out.println(jwt.getClaim("admin"));

        } catch (JWTCreationException | JWTVerificationException exception){
            // 异常处理:无效的签名/过期的令牌/算法不匹配等
            System.out.println(exception.getMessage());
        }
    }

    private  String createToken() throws JWTCreationException {
        Algorithm algorithm = Algorithm.HMAC256(SECRET.getBytes());
        Map<String, Object> headerClaimsMap = new HashMap<>();
        headerClaimsMap.put("alg","HS256");
        headerClaimsMap.put("typ","JWT");
        Map<String, Object> payloadClaimsMap = new HashMap<>();
        payloadClaimsMap.put("sub", "1234567890");
        payloadClaimsMap.put("name","John Doe");
        payloadClaimsMap.put("admin", true);

        return JWT.create()

                // 头部(Header)
                .withHeader(headerClaimsMap)

                // 载荷(Payload)
                .withPayload(payloadClaimsMap)

                // 签名(Signature)
                .withIssuer("auth0")
                // 一天后过期
                .withExpiresAt(new Date(System.currentTimeMillis() + 86400000))
                .sign(algorithm);
    }

    private  DecodedJWT verifyToken(String token) throws JWTVerificationException {
        Algorithm algorithm = Algorithm.HMAC256(SECRET.getBytes());

        return JWT.require(algorithm)
                .withIssuer("auth0") // 检查发行者是否为"auth0"
                .build() // 返回一个JWTVerifier
                .verify(token); // 对JWT进行验证
    }

流程

1. 用户登录

客户端向服务器发送用户名和密码进行认证。
如果提供的凭证正确,服务器会生成一个JWT并将其返回给客户端。

2. JWT 的生成

服务器创建一个包含声明(claims)的JWT。声明是有关实体(通常是用户)和其他数据的陈述。
服务器使用一个密钥或私钥对JWT进行签名。对于对称算法(如HMAC),服务器使用相同的密钥来签名和验证;对于非对称算法(如RSA),则分别使用私钥签名和公钥验证。

3. 客户端保存 JWT

客户端接收到JWT后,通常会将其存储在本地(例如,在浏览器中作为HTTP-only cookie、localStorage 或 sessionStorage 中),以便后续请求时使用。

4. 后续请求

在后续与服务器的通信中,客户端会在每个请求的Authorization头中包含JWT(Bearer )。
服务器接收到来自客户端的请求后,会从请求头中提取JWT,并对其进行验证(检查签名的有效性、过期时间等)。

5. 验证与处理

如果JWT有效,服务器将处理请求并将响应返回给客户端。
如果JWT无效(例如,签名不匹配或令牌已过期),服务器将拒绝请求,通常返回401 Unauthorized状态码。

6. 登出

当用户选择登出时,客户端应当删除保存的JWT以确保它不再被使用。对于存储在HTTP-only cookies中的JWT,可以通过设置过期时间为过去的时间点来实现登出效果。

加密方式

HMAC: 使用相同的密钥进行签名和验证。适用于服务端到服务端通信,当双方都可以安全地持有相同的密钥时。
RSA: 使用私钥签名,公钥验证。适合于开放系统,因为任何人都可以拥有公钥来验证签名,但只有持有私钥的一方能够生成签名。

posted @ 2025-01-24 18:45  zoxm  阅读(55)  评论(0)    收藏  举报