目录

1. JWT 基础概念

1.1 什么是 JWT?

1.2 为什么要用 JWT?

1.3 JWT 的结构

2. JWT 的工作流程

3. Java中操作JWT

3.1 我们先创建 Spring Boot 项目并引入依赖

3.2 再封装一个 JwtUtil 工具类,用于生成和验证 Token。

3.3 实现登录接口

3.4 创建一个拦截器(JwtInterceptor.java)

3.5 配置拦截器

3.6 编写受保护接口

3.7 项目结构图

4. 测试流程

4.1 登录获取 Token

4.2 访问受保护接口

5. 总结


1. JWT 基础概念

1.1 什么是 JWT?

        JWT(JSON Web Token)是一种基于 JSON 的轻量级认证方式,用于在各方之间安全地传递信息。它常用于 前后端分离项目的登录认证,替代传统的 Session 机制。

        特点:数据量小,传输快(轻量)、本身携带用户信息,不依赖服务端存储(自包含)、签名保证数据完整性与可信度(签名防篡改)。


1.2 为什么要用 JWT?

传统的登录认证方式使用 Session 保存用户信息,但在 前后端分离 项目中:

  • Session 需要服务端存储,会增加服务器压力

  • 多台服务器要共享 Session,需要引入 Redis

  • 移动端、小程序调用不方便

JWT(JSON Web Token)

  • 无需服务端保存状态,无状态认证

  • Token 自包含用户信息

  • 轻量、安全、跨平台

1.3 JWT 的结构

        JWT 一般由三部分组成,用 . 分隔:

Header.Payload.Signature

Header(头部)

声明签名算法和类型,例如:

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

alg: 使用的签名算法,如 HS256(HMAC SHA-256)、RS256(RSA SHA-256)等。

typ: 类型,固定为 JWT。

Payload(载荷)

存放实际信息(Claims),分为:

  • Registered claims(注册字段):如 iss(签发者)、exp(过期时间)等

  • Public claims(公共字段):自定义但公开的字段

  • Private claims(私有字段):自定义且内部使用

常用的字段(大家约定俗称的字段,表示一些通用的信息)

字段 含义 示例
sub 用户唯一标识(Subject) "sub": "user_10086"
exp 过期时间(Expiration) "exp": 1723545600(时间戳)
iat 签发时间(Issued At) "iat": 1723459200
iss 签发者(Issuer) "iss": "myapp.com"

⏰ 提醒:exp 最常用,用来控制 token 的有效期。

{
  "sub": "user123",
  "exp": 1723545600,
  "iss": "Yq",
  "iat": 1723459200,
}

自定义信息(这部分是你自己决定要告诉别人的信息)

{
  "name": "Yang",
  "role": "管理员",
  "email": "YangQ@example.com"
}

⚠️ 注意:Payload 是 Base64 编码的,不是加密的! 所以不要在其中存放敏感信息(如密码)。

Signature(签名)

用密钥和前两部分生成的签名,防止数据被篡改。如(使用HMAC SHA256):

HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)

2. JWT 的工作流程

  1. 用户登录 → 服务器验证身份

  2. 服务器生成 JWT 并返回给客户端

  3. 客户端每次请求都带上 JWT(通常放在 HTTP Header 中 Authorization: Bearer <token>

  4. 服务器验证 JWT 的合法性 → 允许访问资源

优点:无状态、轻量、跨域支持
缺点:无法轻易撤销(需维护黑名单)

3. Java中操作JWT

        Java 生态中最流行的 JWT 库是 jjwt,由 Apache 提供,简单易用。

3.1 我们先创建 Spring Boot 项目并引入依赖

<dependencies>
    <!-- Spring Boot Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- JWT -->
    <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.2 再封装一个 JwtUtil 工具类,用于生成和验证 Token。

package com.yg.jwt.util;

import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import java.security.Key;
import java.util.Date;

public class JwtUtil {
    // 建议从配置文件读取
    private static final Key key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
    private static final long EXPIRATION = 60 * 1000; // 1分钟

    // 生成 Token
    public static String generateToken(String username, String role) {
        return Jwts.builder()
                .setSubject(username)
                .claim("role", role)
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION))
                .signWith(key)
                .compact();
    }

    // 解析 Token
    public static Claims parseToken(String token) {
        return Jwts.parserBuilder()
                .setSigningKey(key)
                .build()
                .parseClaimsJws(token)
                .getBody();
    }
}

3.3 实现登录接口

package com.yg.jwt.controller;

import org.springframework.web.bind.annotation.*;
import com.yg.jwt.util.JwtUtil;

import java.util.HashMap;
import java.util.Map;

@RestController
@RequestMapping("/auth")
public class AuthController {

    @PostMapping("/login")
    public Map<String, Object> login(@RequestParam String username, @RequestParam String password) {
        Map<String, Object> result = new HashMap<>();

        // 模拟账号密码验证
        if ("admin".equals(username) && "123456".equals(password)) {
            String token = JwtUtil.generateToken(username, "admin");
            result.put("code", 200);
            result.put("message", "登录成功");
            result.put("token", token);
        } else {
            result.put("code", 401);
            result.put("message", "用户名或密码错误");
        }
        return result;
    }
}

3.4 创建一个拦截器(JwtInterceptor.java)

拦截请求,用来验证 Token 是否有效。

package com.yg.jwt.interceptor;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import com.yg.jwt.util.JwtUtil;


@Component
public class JwtInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String authHeader = request.getHeader("Authorization");

        if (authHeader != null && authHeader.startsWith("Bearer ")) {
            String token = authHeader.substring(7);

            try {
                Claims claims = JwtUtil.parseToken(token);
                request.setAttribute("username", claims.getSubject());
                request.setAttribute("role", claims.get("role"));
                return true;
            } catch (ExpiredJwtException e) {
                response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                response.getWriter().write("Token 已过期");
                return false;
            } catch (Exception e) {
                response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                response.getWriter().write("无效 Token");
                return false;
            }
        }
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        response.getWriter().write("缺少 Token");
        return false;
    }
}

3.5 配置拦截器

package com.yg.jwt.config;


import com.yg.jwt.interceptor.JwtInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    private JwtInterceptor jwtInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(jwtInterceptor)
                .addPathPatterns("/**")
                .excludePathPatterns("/auth/login"); // 登录接口放行
    }
}

💡 小插曲:为什么要配置拦截器?

因为MVC 框架需要知道“有哪些拦截器要工作”(注册机制)、统一处理(避免在每个 Controller 里重复写验证逻辑)、全局控制(可以精确控制拦截哪些路径、放行哪些路径)、流程集成(拦截器是 MVC 生命周期的一部分,必须接入流程)

3.6 编写受保护接口

package com.yg.jwt.controller;

import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/user")
public class UserController {

    @GetMapping("/info")
    public String getUserInfo(@RequestAttribute("username") String username,
                              @RequestAttribute("role") String role) {
        return "当前用户:" + username + ",角色:" + role;
    }
}

3.7 项目结构图

jwt
│── pom.xml                # Maven 依赖
│── src
│   ├── main
│   │   ├── java
│   │   │   └── com.yq.jwt
│   │   │       ├── config
│   │   │       │    └── WebConfig.java          # 配置拦截器
│   │   │       ├── controller
│   │   │       │    ├── AuthController.java     # 登录接口
│   │   │       │    └── UserController.java     # 受保护接口
│   │   │       ├── interceptor
│   │   │       │    └── JwtInterceptor.java     # JWT 拦截器
│   │   │       └── util
│   │   │            └── JwtUtil.java            # JWT 工具类
│   │   └── resources
│   │        └── application.yml                 # 配置文件
│   └── test                                     
│        └── java                                 # 测试代码

4. 测试流程

本篇章用的测试工具为Apifox,使用其他测试工具也是可以的(如:Postman)。

4.1 登录获取 Token

POST http://localhost:8080/auth/login
参数:
username=admin
password=123456

返回:

4.2 访问受保护接口

GET http://localhost:8080/user/info
Header:
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9...

把刚刚从后端返回回来的token放到Headers里面,接着访问后端请求数据

5. 总结

        JWT 是一种轻量、跨域、无状态的认证方式,非常适合现代 Web 和微服务架构。通过 Java 的 jjwt 库,我们可以快速生成、解析和验证 JWT,实现安全的身份验证机制。

💬 如果你想要完整的 Spring Boot + JWT 登录认证项目源码,可以在评论区留言。

💬如果你觉得这篇文章有帮助,别忘了点赞、分享!👍

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐