JWT(JSON Web Token)

JWT(JSON Web Token)是一种用于在各方之间作为 JSON 对象安全传输信息的开放标准(RFC 7519)。它是自包含的,既可以被验证,也可以被信任,因为它是通过数字签名的。JWT 在许多现代应用中用于身份验证和授权。

JWT 的结构

JWT 由三部分组成:Header(头部)、Payload(负载)、Signature(签名)。每部分使用 Base64Url 编码,并用点号(.)分隔。

  1. Header:

    • 包含令牌类型(JWT)和签名算法(如 HMAC SHA256 或 RSA)。
    json 复制代码
    {
      "alg": "HS256",
      "typ": "JWT"
    }
  2. Payload:

    • 包含声明(claims),即实体(通常是用户)及附加数据。标准声明包括 iss(签发者)、exp(过期时间)、sub(主题)等。
    json 复制代码
    {
      "sub": "1234567890",
      "name": "John Doe",
      "iat": 1516239022
    }
  3. Signature:

    • 用于验证令牌的发送方及数据完整性。将编码后的 Header 和 Payload 通过指定算法进行签名。
    plaintext 复制代码
    HMACSHA256(
      base64UrlEncode(header) + "." +
      base64UrlEncode(payload),
      secret)

JWT 的工作流程

  1. 客户端登录:用户使用其凭据登录,服务器验证身份后生成 JWT,并将其返回给客户端。
  2. 客户端存储 JWT:客户端将 JWT 存储在本地存储、cookie 或其他安全位置。
  3. 客户端请求资源 :客户端在每个请求的 HTTP 头部添加 JWT(通常在 Authorization: Bearer <token>)。
  4. 服务器验证 JWT:服务器验证 JWT 的签名和有效性(如过期时间)。验证通过后,服务器处理请求并返回相应的数据。

Spring Security 与 JWT 集成

Spring Security 提供了与 JWT 集成的强大支持。以下是一个简单的示例,展示如何使用 Spring Security 和 JWT 进行身份验证和授权。

依赖

pom.xml 中添加必要的依赖:

xml 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>
配置类

创建一个配置类,配置 Spring Security 和 JWT 验证。

java 复制代码
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
            .authorizeRequests()
            .antMatchers("/login").permitAll()
            .anyRequest().authenticated()
            .and()
            .addFilter(new JWTAuthenticationFilter(authenticationManager()))
            .addFilter(new JWTAuthorizationFilter(authenticationManager()));
    }

    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }
}
JWT 工具类

创建一个工具类用于生成和验证 JWT。

java 复制代码
public class JWTUtil {

    private static final String SECRET_KEY = "your_secret_key";

    public static String generateToken(Authentication auth) {
        return Jwts.builder()
            .setSubject(auth.getName())
            .setExpiration(new Date(System.currentTimeMillis() + 864_000_000)) // 10 days
            .signWith(SignatureAlgorithm.HS512, SECRET_KEY.getBytes())
            .compact();
    }

    public static Claims getClaims(String token) {
        return Jwts.parser()
            .setSigningKey(SECRET_KEY.getBytes())
            .parseClaimsJws(token)
            .getBody();
    }

    public static boolean validateToken(String token) {
        try {
            Jwts.parser().setSigningKey(SECRET_KEY.getBytes()).parseClaimsJws(token);
            return true;
        } catch (JwtException | IllegalArgumentException e) {
            return false;
        }
    }
}
认证过滤器

创建一个过滤器用于处理登录认证。

java 复制代码
public class JWTAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

    private AuthenticationManager authenticationManager;

    public JWTAuthenticationFilter(AuthenticationManager authenticationManager) {
        this.authenticationManager = authenticationManager;
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res) throws AuthenticationException {
        try {
            User creds = new ObjectMapper().readValue(req.getInputStream(), User.class);
            return authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(
                    creds.getUsername(),
                    creds.getPassword(),
                    new ArrayList<>())
            );
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    protected void successfulAuthentication(HttpServletRequest req, HttpServletResponse res, FilterChain chain, Authentication auth) throws IOException, ServletException {
        String token = JWTUtil.generateToken(auth);
        res.addHeader("Authorization", "Bearer " + token);
    }
}
授权过滤器

创建一个过滤器用于处理请求授权。

java 复制代码
public class JWTAuthorizationFilter extends BasicAuthenticationFilter {

    public JWTAuthorizationFilter(AuthenticationManager authManager) {
        super(authManager);
    }

    @Override
    protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws IOException, ServletException {
        String header = req.getHeader("Authorization");

        if (header == null || !header.startsWith("Bearer ")) {
            chain.doFilter(req, res);
            return;
        }

        UsernamePasswordAuthenticationToken authentication = getAuthentication(req);

        SecurityContextHolder.getContext().setAuthentication(authentication);
        chain.doFilter(req, res);
    }

    private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
        String token = request.getHeader("Authorization");
        if (token != null) {
            String user = JWTUtil.getClaims(token.replace("Bearer ", "")).getSubject();
            if (user != null) {
                return new UsernamePasswordAuthenticationToken(user, null, new ArrayList<>());
            }
            return null;
        }
        return null;
    }
}

总结

JWT 提供了一种简洁而强大的方式来进行身份验证和授权,特别适用于分布式系统和微服务架构。Spring Security 通过其强大的扩展机制,使得与 JWT 的集成变得非常简单和高效。通过了解和应用这些技术,开发者可以构建出安全、可靠的现代 Web 应用。

相关推荐
一人の梅雨6 分钟前
中国制造网商品详情接口进阶实战:跨境场景下的差异化适配与问题攻坚
java·前端·javascript
无心水7 分钟前
8、吃透Go语言container包:链表(List)与环(Ring)的核心原理+避坑指南
java·开发语言·链表·微服务·架构·golang·list
沛沛老爹7 分钟前
Web开发者转型AI安全核心:Agent金融数据处理Skill合规架构实战
java·人工智能·rag·企业转型·合规
源代码•宸7 分钟前
Golang原理剖析(Go语言垃圾回收GC)
经验分享·后端·算法·面试·golang·stw·三色标记
步步为营DotNet8 分钟前
深度钻研.NET 中Task.Run:异步任务执行的便捷入口
java·服务器·.net
Hello.Reader8 分钟前
Spring 新声明式 HTTP 客户端:HTTP Interface + RestClient,把“调用外部 API”写成接口
java·spring·http
Dream_sky分享14 分钟前
IDEA 2025中git的Local Changes找不到
java·git·intellij-idea
若鱼191915 分钟前
SpringBoot4.0新特性-声明式HTTP远程调用客户端进阶篇
java·spring
xzl0419 分钟前
小智服务器:设备的各种MCP消息、初始化响应、工具列表和工具调用响应
java·网络·python
夜勤月21 分钟前
拒绝线程死锁与调度延迟:深度实战 C++ 内存模型与无锁队列,构建高并发系统级中枢
java·c++·spring