Java JWT原理及工作流程

 更新时间:2025年05月16日 16:35:49   作者:jkoya  
JWT 是一种简单而强大的身份验证机制,适用于各种前后端分离的项目,通过本文的介绍,你应该对 JWT 的原理、工作流程和使用方法有了更深入的了解,感兴趣的朋友跟随小编一起看看吧

引言

在当代 Web 应用与 API 开发里,用户认证和授权无疑是极为关键的环节。JSON Web Token(JWT)作为一种轻量级的身份验证机制,凭借其简洁性、可扩展性以及跨域支持等显著优势,在众多前后端分离项目中得到了广泛应用。本文将全面深入地探讨 JWT 的原理、工作流程,并且结合 Java 代码示例,展示如何在一个简单的登录系统中运用 JWT 进行认证。

一、JWT 概述

1. 什么是 JWT

JWT 是一种用于在网络应用间安全传递声明的开放标准(RFC 7519)。它通常由三部分构成:头部(Header)、载荷(Payload)和签名(Signature),并以 . 分隔,形成类似 xxxxx.yyyyy.zzzzz 的字符串。

2. JWT 的结构

头部(Header):通常包含两部分信息,令牌的类型(通常是 JWT)和使用的签名算法,如 HMAC SHA256 或 RSA。它是一个 JSON 对象,经过 Base64Url 编码后形成 JWT 的第一部分。

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

载荷(Payload):包含声明(Claims),声明是关于实体(通常是用户)和其他数据的声明。声明分为三种类型:注册声明、公开声明和私有声明。注册声明是一些预定义的声明,如 iss(发行人)、sub(主题)、aud(受众)等。载荷也是一个 JSON 对象,经过 Base64Url 编码后形成 JWT 的第二部分。

{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022
}

签名(Signature):为了创建签名部分,需要使用编码后的头部、编码后的载荷、一个密钥(secret)和头部中指定的签名算法。签名用于验证消息在传递过程中没有被更改,并且在使用私钥签名的情况下,还可以验证 JWT 的发送者的身份。

3. JWT 的优点

  • 无状态:JWT 是无状态的,服务器不需要存储会话信息,因此可以很容易地扩展到多个服务器或微服务架构中。
  • 跨域支持:由于 JWT 可以通过 HTTP 头部或 URL 参数传递,因此可以在不同的域之间安全地使用。
  • 可扩展性:可以在载荷中添加自定义声明,以满足不同的业务需求。

二、JWT 工作流程

1. 用户登录

用户向服务器发送登录请求,提供用户名和密码。

2. 服务器验证

服务器验证用户的用户名和密码,如果验证成功,服务器根据用户信息生成一个 JWT。

3. 返回 JWT

服务器将生成的 JWT 返回给客户端。

4. 客户端存储

客户端接收到 JWT 后,将其存储在本地,通常是在浏览器的 localStoragesessionStorage 中。

5. 后续请求

在后续的请求中,客户端将 JWT 包含在请求的头部(通常是 Authorization 头部)中发送给服务器。

6. 服务器验证 JWT

服务器接收到请求后,验证 JWT 的签名和有效期。如果验证成功,服务器认为用户是合法的,并处理请求。

三、代码示例:使用 JWT 实现登录认证

1. 项目环境

我们使用 Java 和 Spring Boot 框架来实现一个简单的登录系统,并使用 io.jsonwebtoken 库来处理 JWT。

2. 引入依赖

pom.xml 中添加以下依赖:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt-api</artifactId>
        <version>0.11.5</version>
    </dependency>
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt-impl</artifactId>
        <version>0.11.5</version>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt-jackson</artifactId>
        <version>0.11.5</version>
        <scope>runtime</scope>
    </dependency>
</dependencies>

3. 代码实现

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.web.bind.annotation.*;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/api")
public class AuthController {
    // 密钥,用于签名和验证 JWT
    private static final String SECRET_KEY = "your_secret_key";
    // 有效期,设置为 30 分钟
    private static final long EXPIRATION_TIME = 30 * 60 * 1000;
    // 模拟用户数据库
    private static final Map<String, String> users = new HashMap<>();
    static {
        users.put("user1", "password1");
        users.put("user2", "password2");
    }
    // 生成 JWT
    private String generateToken(String username) {
        Date now = new Date();
        Date expiration = new Date(now.getTime() + EXPIRATION_TIME);
        return Jwts.builder()
               .setSubject(username)
               .setIssuedAt(now)
               .setExpiration(expiration)
               .signWith(SignatureAlgorithm.HS256, SECRET_KEY)
               .compact();
    }
    // 验证 JWT
    private Claims validateToken(String token) {
        try {
            return Jwts.parser()
                   .setSigningKey(SECRET_KEY)
                   .parseClaimsJws(token)
                   .getBody();
        } catch (Exception e) {
            return null;
        }
    }
    // 登录接口
    @PostMapping("/login")
    public String login(@RequestBody Map<String, String> credentials) {
        String username = credentials.get("username");
        String password = credentials.get("password");
        if (users.containsKey(username) && users.get(username).equals(password)) {
            return generateToken(username);
        }
        return "Invalid credentials";
    }
    // 受保护的接口
    @GetMapping("/protected")
    public String protectedResource(@RequestHeader("Authorization") String token) {
        if (token == null ||!token.startsWith("Bearer ")) {
            return "Token is missing";
        }
        token = token.substring(7);
        Claims claims = validateToken(token);
        if (claims != null) {
            return "Welcome, " + claims.getSubject();
        }
        return "Invalid token";
    }
}

4. 代码解释

  • generateToken 方法:根据用户的用户名生成一个 JWT,包含用户名、签发时间和有效期。
  • validateToken 方法:验证 JWT 的签名和有效期,如果验证成功,返回载荷信息。
  • /login 接口:处理用户的登录请求,验证用户名和密码,如果验证成功,生成并返回 JWT。
  • /protected 接口:受保护的接口,需要在请求头部中包含有效的 JWT 才能访问。

5. 测试

你可以使用 Postman 或者其他工具来测试接口:

  • 登录请求

发送一个 POST 请求到 http://localhost:8080/api/login,请求体为 {"username": "user1", "password": "password1"}

  • 受保护的请求

发送一个 GET 请求到 http://localhost:8080/api/protected,并在请求头中添加 Authorization: Bearer <your_token>

四、JWT 的安全注意事项

  • 密钥安全:密钥是 JWT 签名和验证的关键,必须妥善保管,避免泄露。
  • 有效期设置:合理设置 JWT 的有效期,避免过长的有效期导致安全风险。
  • 防止重放攻击:可以使用一次性令牌或添加时间戳等方式来防止重放攻击。

五、总结

JWT 是一种简单而强大的身份验证机制,适用于各种前后端分离的项目。通过本文的介绍,你应该对 JWT 的原理、工作流程和使用方法有了更深入的了解。在实际开发中,要注意 JWT 的安全问题,确保系统的安全性。希望本文能帮助你在项目中成功应用 JWT 进行登录认证。

到此这篇关于Java JWT详细讲解的文章就介绍到这了,更多相关Java JWT内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java类成员访问权限控制知识总结

    Java类成员访问权限控制知识总结

    这篇文章主要介绍了Java类成员访问权限控制知识总结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-04-04
  • IDEA快速搭建Java开发环境的教程图解

    IDEA快速搭建Java开发环境的教程图解

    这篇文章主要介绍了IDEA如何快速搭建Java开发环境,本文通过图文并茂的形式给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-11-11
  • Java基于Tcp协议的socket编程实例

    Java基于Tcp协议的socket编程实例

    这篇文章主要介绍了Java基于Tcp协议的socket编程实例,较为详细的分析了socket编程客户端与服务器端的具体实现步骤与使用技巧,具有一定的参考借鉴价值,需要的朋友可以参考下
    2014-12-12
  • Java8 Collectors求和功能的自定义扩展操作

    Java8 Collectors求和功能的自定义扩展操作

    这篇文章主要介绍了Java8 Collectors求和功能的自定义扩展操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-02-02
  • 解读Java报错输出的信息究竟是什么

    解读Java报错输出的信息究竟是什么

    Java报错输出的信息主要包括异常的主要描述信息和当前线程的栈帧信息,栈帧是虚拟机栈的基本存储单元,主要由局部变量表、操作数栈和帧数据三部分组成,局部变量表用于存放方法的参数和局部变量,操作数栈用于保存计算过程中产生的中间结果
    2024-12-12
  • 深入解析SpringBoot中#{}和${}的使用

    深入解析SpringBoot中#{}和${}的使用

    本文主要介绍了深入解析SpringBoot中#{}和${}的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2025-04-04
  • Java基本数据类型包装类原理解析

    Java基本数据类型包装类原理解析

    这篇文章主要介绍了Java基本数据类型包装类原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-05-05
  • java应用开发之JVM运行时内存分析

    java应用开发之JVM运行时内存分析

    这篇文章主要介绍了java应用开发之JVM运行时内存,文中附含图文示例内容分析非常简要,有需要的朋友可以借鉴参考下,希望能够有所帮助
    2021-09-09
  • 在springboot中拦截器Filter中注入bean失败问题及解决

    在springboot中拦截器Filter中注入bean失败问题及解决

    这篇文章主要介绍了在springboot中拦截器Filter中注入bean失败问题及解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-05-05
  • SpringBoot中如何统一接口返回与全局异常处理详解

    SpringBoot中如何统一接口返回与全局异常处理详解

    全局异常处理是个比较重要的功能,一般在项目里都会用到,这篇文章主要给大家介绍了关于SpringBoot中如何统一接口返回与全局异常处理的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下
    2021-09-09

最新评论