You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot 3 Security无用户场景下JWT验证方案咨询

可行,这两种Spring Security实现方式满足你的需求

你完全可以用Spring Security实现仅验证JWT有效性、无需用户服务/数据库的需求,不需要自己写独立的请求过滤器,以下是两种标准实现方式:

方式一:基于Spring Security OAuth2 Resource Server(推荐,简洁规范)

这是Spring官方推荐的资源服务JWT验证方案,无需自定义过滤器,仅需配置即可完成Token验证。

  1. 添加依赖
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
  1. 配置密钥(application.yml)
spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          secret-key: your-known-secret-key-here # 替换为你的实际密钥
  1. 安全配置类
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                .csrf(csrf -> csrf.disable()) // REST接口无需CSRF保护
                .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) // 无状态会话
                .authorizeHttpRequests(auth -> auth
                        .anyRequest().authenticated() // 所有请求需通过认证
                )
                .oauth2ResourceServer(oauth2 -> oauth2.jwt(jwt -> {})); // 启用JWT资源服务验证

        return http.build();
    }
}

该方案会自动解析Authorization: Bearer <token>请求头,验证签名和Token有效期,无效时自动返回401状态码,完全不需要用户服务或数据库。

方式二:自定义JWT验证过滤器(灵活可控)

如果需要对Token验证逻辑做自定义扩展,比如额外校验特定Claims字段,可以用这种方式:

  1. 添加依赖(含JJWT用于JWT解析)
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</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>
  1. 自定义JWT验证过滤器
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.crypto.SecretKey;
import java.io.IOException;
import java.util.Collections;

public class JwtValidationFilter extends OncePerRequestFilter {

    private final SecretKey secretKey;

    public JwtValidationFilter(String secret) {
        this.secretKey = Keys.hmacShaKeyFor(secret.getBytes());
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String authHeader = request.getHeader("Authorization");

        if (authHeader == null || !authHeader.startsWith("Bearer ")) {
            filterChain.doFilter(request, response);
            return;
        }

        String token = authHeader.substring(7);

        try {
            // 仅验证Token签名和有效期
            Jwts.parserBuilder()
                    .setSigningKey(secretKey)
                    .build()
                    .parseClaimsJws(token);

            // 创建占位认证对象(无需真实用户信息,仅标记已认证)
            Authentication auth = new UsernamePasswordAuthenticationToken(
                    "anonymous",
                    null,
                    Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER"))
            );
            SecurityContextHolder.getContext().setAuthentication(auth);
        } catch (Exception e) {
            // Token无效时返回401
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.getWriter().write("Invalid JWT Token");
            return;
        }

        filterChain.doFilter(request, response);
    }
}
  1. 安全配置类
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    private final String jwtSecret = "your-known-secret-key-here"; // 建议从配置文件读取

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                .csrf(csrf -> csrf.disable())
                .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .authorizeHttpRequests(auth -> auth
                        .anyRequest().authenticated()
                )
                // 将自定义过滤器添加到UsernamePassword认证过滤器之前
                .addFilterBefore(new JwtValidationFilter(jwtSecret), UsernamePasswordAuthenticationFilter.class);

        return http.build();
    }
}

注意点

  • 两种方式都无需用户服务或数据库,仅通过已知密钥验证Token有效性;
  • 若需要统一处理401响应,可以自定义AuthenticationEntryPoint替换过滤器中的直接响应,更符合Spring Security规范;
  • 密钥建议通过配置文件注入,避免硬编码。

内容的提问来源于stack exchange,提问作者Nerospeed

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 15:10:59