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

Spring Authorization Server客户端凭证流获取Token失败(401错误)

基于Spring Authorization Server搭建授权服务器,Postman测试始终返回401未授权

问题描述

我正在基于Spring Authorization Server搭建授权服务器,使用Postman测试时始终收到401未授权响应。已附上Postman请求截图与控制台错误截图,以下是使用的两个配置文件代码:

DefaultSecurityConfig.java

@Configuration(proxyBeanMethods = false)
public class DefaultSecurityConfig {

    // @formatter:off
    @Bean
    public   SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
        http.authorizeRequests(authorizeRequests ->
        authorizeRequests.anyRequest().authenticated()
    )
    .formLogin(withDefaults());
        return http.build();
    }
    // @formatter:on

    @Bean
    public UserDetailsService users() {
        UserDetails user = User.withDefaultPasswordEncoder()
                .username("user1")
                .password("password")
                .roles("USER")
                .build();
        return new InMemoryUserDetailsManager(user);
    }
    // @formatter:on

    @Bean
    public SessionRegistry sessionRegistry() {
        return new SessionRegistryImpl();
    }

    @Bean
    public HttpSessionEventPublisher httpSessionEventPublisher() {
        return new HttpSessionEventPublisher();
    }

}

AuthorizationServerConfig.java

@ComponentScan(basePackageClasses = AuthorizationServerConfig.class)

public class AuthorizationServerConfig {


  @Bean
  @Order(Ordered.HIGHEST_PRECEDENCE)
  public SecurityFilterChain authServerSecurityFilterChain(HttpSecurity http) throws Exception {
    OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
    return http.formLogin(Customizer.withDefaults()).build();
  }

  @Bean
  @ConditionalOnMissingBean
  public RegisteredClientRepository registeredClientRepository() {

    RegisteredClient codeClient = RegisteredClient.withId(UUID.randomUUID().toString())
    .clientId("code-auth-client")
    .clientSecret("abcde")
    .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
    .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_POST)
    .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
    .authorizationGrantType(AuthorizationGrantType.JWT_BEARER)
    .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
    .authorizationGrantType(AuthorizationGrantType.PASSWORD)
    .redirectUri("http://127.0.0.1:8080/redirect/")
    .scope("read-access")
    .build();

    return new InMemoryRegisteredClientRepository(codeClient);
  }

}

问题排查与修复方案

1. 客户端密码未加密

Spring Authorization Server默认要求客户端密码必须加密存储,当前配置中直接使用明文abcde会导致认证失败。

  • 新增PasswordEncoder Bean:
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
    
  • 加密客户端密码后替换原明文:
    .clientSecret(passwordEncoder.encode("abcde"))
    

2. SecurityFilterChain优先级冲突

DefaultSecurityConfig中的defaultSecurityFilterChain未指定Order,会和授权服务器的高优先级FilterChain产生冲突,导致授权端点的配置未生效。

  • 给defaultSecurityFilterChain设置低于授权服务器的优先级:
    @Bean
    @Order(2)
    public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
        // 原有代码
    }
    

3. 表单登录配置重复

两个SecurityFilterChain都配置了formLogin,可能导致认证流程混乱。可以移除DefaultSecurityConfig中的formLogin配置,只保留授权服务器配置中的表单登录。

4. Postman请求参数校验

使用授权码模式请求/oauth2/authorize时,需确保:

  • 客户端ID(code-auth-client)和密码(加密后的abcde)正确
  • redirect_uri完全匹配配置中的http://127.0.0.1:8080/redirect/
  • 请求参数包含response_type=code、scope=read-access

调整后的完整配置示例

DefaultSecurityConfig.java

@Configuration(proxyBeanMethods = false)
public class DefaultSecurityConfig {

    // @formatter:off
    @Bean
    @Order(2)
    public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
        http.authorizeRequests(authorizeRequests ->
                authorizeRequests.anyRequest().authenticated()
        );
        return http.build();
    }
    // @formatter:on

    @Bean
    public UserDetailsService users() {
        UserDetails user = User.withDefaultPasswordEncoder()
                .username("user1")
                .password("password")
                .roles("USER")
                .build();
        return new InMemoryUserDetailsManager(user);
    }

    @Bean
    public SessionRegistry sessionRegistry() {
        return new SessionRegistryImpl();
    }

    @Bean
    public HttpSessionEventPublisher httpSessionEventPublisher() {
        return new HttpSessionEventPublisher();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

AuthorizationServerConfig.java

@Configuration
@ComponentScan(basePackageClasses = AuthorizationServerConfig.class)
public class AuthorizationServerConfig {

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SecurityFilterChain authServerSecurityFilterChain(HttpSecurity http) throws Exception {
        OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
        return http.formLogin(Customizer.withDefaults()).build();
    }

    @Bean
    @ConditionalOnMissingBean
    public RegisteredClientRepository registeredClientRepository() {

        RegisteredClient codeClient = RegisteredClient.withId(UUID.randomUUID().toString())
                .clientId("code-auth-client")
                .clientSecret(passwordEncoder.encode("abcde"))
                .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
                .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_POST)
                .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
                .authorizationGrantType(AuthorizationGrantType.JWT_BEARER)
                .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
                .authorizationGrantType(AuthorizationGrantType.PASSWORD)
                .redirectUri("http://127.0.0.1:8080/redirect/")
                .scope("read-access")
                .build();

        return new InMemoryRegisteredClientRepository(codeClient);
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 09:11:59