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 应用。

相关推荐
书源丶42 分钟前
三十六、File 类与 IO 流基础——文件操作的「第一步」
java
刀法如飞1 小时前
Go数组去重的20种实现方式,AI时代解决问题的不同思路
后端·算法·go
AI人工智能+电脑小能手1 小时前
【大白话说Java面试题】【Java基础篇】第30题:JDK动态代理和CGLIB动态代理有什么区别
java·开发语言·后端·面试·代理模式
swipe1 小时前
别再把 AI 聊天做成纯文本:从 agui 这个前后端项目,拆解“可感知工具调用”的流式 AI UI
后端·langchain·llm
GetcharZp1 小时前
GitHub 爆火!纯 Go 编写的文件同步神器 Syncthing,凭什么成为程序员的标配?
后端
hERS EOUS2 小时前
SpringBoot 使用 spring.profiles.active 来区分不同环境配置
spring boot·后端·spring
DFT计算杂谈2 小时前
wannier90 参数详解大全
java·前端·css·html·css3
LucianaiB2 小时前
我用飞书多维表做了一个 AI 活动推荐智能体:每天自动催我别错过截止日期!
后端
marsh02062 小时前
43 openclaw熔断与降级:保障系统在异常情况下的可用性
java·运维·网络·ai·编程·技术
张健11564096482 小时前
临界区和同一线程上锁
java·开发语言·jvm