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

Spring Boot多认证配置:HS256 JWT与OAuth2共存实现问询

可以实现,具体方案如下

核心思路是给目标端点配置多认证过滤器链:让自定义的HS256 JWT认证过滤器优先执行,若认证失败则不终止请求链,继续执行原有的OAuth2资源服务器过滤器。以下是分步实现细节:

1. 配置HS256对称密钥的JWT解码器与认证管理器

首先创建HS256专用的JWT解码器和认证管理器,用于验证对称签名的令牌:

import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.JwtAuthenticationProvider;
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
import org.springframework.security.oauth2.core.OAuth2TokenValidator;
import org.springframework.security.oauth2.jwt.JwtValidators;
import org.springframework.security.oauth2.jwt.MacAlgorithm;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;

@Value("${app.hs256.secret}") // 从配置文件读取HS256对称密钥
private String hs256Secret;

@Bean
public JwtDecoder hs256JwtDecoder() {
    SecretKey secretKey = new SecretKeySpec(
            hs256Secret.getBytes(StandardCharsets.UTF_8),
            MacAlgorithm.HS256.getName()
    );
    NimbusJwtDecoder decoder = NimbusJwtDecoder.withSecretKey(secretKey)
            .macAlgorithm(MacAlgorithm.HS256)
            .build();
    // 可选:添加令牌有效期等通用校验
    OAuth2TokenValidator<Jwt> validator = JwtValidators.createDefault();
    decoder.setJwtValidator(validator);
    return decoder;
}

@Bean
public AuthenticationManager hs256AuthenticationManager(JwtDecoder hs256JwtDecoder) {
    JwtAuthenticationProvider provider = new JwtAuthenticationProvider(hs256JwtDecoder);
    // 可选:如果HS256令牌需要解析scope权限,配置转换器
    // provider.setJwtAuthenticationConverter(hs256JwtAuthenticationConverter());
    return new ProviderManager(provider);
}

// 可选:HS256令牌的scope权限转换器(若需要和原有OAuth2权限规则兼容)
// @Bean
// public JwtAuthenticationConverter hs256JwtAuthenticationConverter() {
//     JwtGrantedAuthoritiesConverter authoritiesConverter = new JwtGrantedAuthoritiesConverter();
//     authoritiesConverter.setAuthorityPrefix("SCOPE_");
//     authoritiesConverter.setScopeAttributeName("scope");
//
//     JwtAuthenticationConverter converter = new JwtAuthenticationConverter();
//     converter.setJwtGrantedAuthoritiesConverter(authoritiesConverter);
//     return converter;
// }

2. 自定义HS256认证过滤器

继承AbstractAuthenticationProcessingFilter,仅处理目标端点,且认证失败后不终止请求链,让后续的OAuth2过滤器继续尝试:

import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class HS256JwtAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    public HS256JwtAuthenticationFilter(AuthenticationManager authenticationManager) {
        // 指定仅处理目标端点
        super("/api/target-endpoint-1/**", "/api/target-endpoint-2/**");
        setAuthenticationManager(authenticationManager);
        
        // 配置认证失败逻辑:清空上下文,继续执行后续过滤器
        setAuthenticationFailureHandler((request, response, exception) -> {
            SecurityContextHolder.clearContext();
            getSuccessHandler().onAuthenticationSuccess(request, response, null);
        });
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
        String token = extractBearerToken(request);
        if (token == null) {
            throw new BadCredentialsException("No Bearer token found in request");
        }
        // 解析令牌并封装为认证请求
        Jwt jwt = ((JwtDecoder) getAuthenticationManager().getProviders().get(0).getJwtDecoder()).decode(token);
        JwtAuthenticationToken authRequest = new JwtAuthenticationToken(jwt);
        return getAuthenticationManager().authenticate(authRequest);
    }

    // 从请求头提取Bearer令牌
    private String extractBearerToken(HttpServletRequest request) {
        String authHeader = request.getHeader("Authorization");
        if (authHeader != null && authHeader.startsWith("Bearer ")) {
            return authHeader.substring(7);
        }
        return null;
    }
}

3. 修改原有SecurityFilterChain配置

将自定义的HS256过滤器添加到OAuth2资源服务器过滤器之前,并调整目标端点的授权规则:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http, AuthenticationManager hs256AuthenticationManager) throws Exception {
    if (properties.isSecured()) {
        // 注册自定义HS256过滤器
        HS256JwtAuthenticationFilter hs256Filter = new HS256JwtAuthenticationFilter(hs256AuthenticationManager);
        
        http.cors(Customizer.withDefaults())
                .csrf(AbstractHttpConfigurer::disable)
                .authorizeHttpRequests(authorize -> authorize
                        .requestMatchers("/actuator/**", "/system/v1/resources").permitAll()
                        // 目标端点允许两种认证方式通过
                        .requestMatchers("/api/target-endpoint-1/**", "/api/target-endpoint-2/**").authenticated()
                        .anyRequest().access(hasScope(SCOPE))
                )
                // 将HS256过滤器放在OAuth2资源服务器过滤器之前
                .addFilterBefore(hs256Filter, OAuth2ResourceServerFilter.class)
                .oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()));
    }
    return http.build();
}

关键注意事项

  • HS256对称密钥需妥善保管,建议通过环境变量或加密配置文件加载,避免硬编码。
  • 若HS256令牌需要兼容原有hasScope(SCOPE)的授权规则,需配置JwtAuthenticationConverter解析令牌中的scope字段,生成对应权限。
  • 自定义过滤器的失败处理必须清空Security上下文,否则会影响后续OAuth2认证的执行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 09:01:18