Spring Authorization Server客户端凭证流获取Token失败(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会导致认证失败。
- 新增
PasswordEncoderBean:@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
相关产品推荐
相关产品推荐

