我有一个带有spring-security-oauth2-autoconfigure的Spring引导应用程序。资源服务器和授权服务器在同一应用程序中运行。
应用程序具有一个通过WebSecurityConfiguration全局配置的用户详细信息服务。它用于资源的所有者身份验证。
我已将授权服务器配置为使用内存中的存储对客户端进行身份验证,如下所示:
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("devglan-client")
.secret("$2a$04$e/c1/RfsWuThaWFCrcCuJeoyvwCV0URN/6Pn9ZFlrtIWaU/vj/BfG")
.authorizedGrantTypes("implicit","refresh_token", "password", "authorization_code")
.scopes("read write trust");
}
当我尝试使用GET授权端点获取授权代码时,Spring Security会尝试使用用户详细信息服务来认证应用程序客户端。
我在请求中包含一个带有基本选项的HTTP授权标头,其中包含cliend_id:client_secret凭据。
GET /oauth/authorize?
response_type=code&client_id=bpclient&scope=read HTTP/1.1
Host: localhost:8080
Accept: application/json
Content-Type: application/x-www-form-urlencoded
Authorization: Basic ZGV2Z2xhbi1jbGllbnQ6MTIzNDU2
Cache-Control: no-cache
Postman-Token: 77dd0129-bb86-d039-d252-8e7d483092f2
我调试了代码,并发现DaoAuthenticationProvider尝试使用用户详细信息服务来检索应用程序客户端凭据。
为什么Spring OAuth使用用户详细信息服务在oauth授权流程而不是内存中配置中对应用程序客户端进行身份验证?
Pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
<version>2.0.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-jose</artifactId>
</dependency>
应用程序主要
@SpringBootApplication()
@EnableAutoConfiguration
public class Application extends RepositoryRestConfigurerAdapter{
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
授权服务器配置:
@Configuration
@EnableAuthorizationServer
public class ServidorAutorizacaoOAuthConfiguracao extends AuthorizationServerConfigurerAdapter {
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("devglan-client")
.secret("$2a$04$e/c1/RfsWuThaWFCrcCuJeoyvwCV0URN/6Pn9ZFlrtIWaU/vj/BfG")
.authorizedGrantTypes("implicit","refresh_token", "password", "authorization_code")
.scopes("read write trust");
}
}
WebSecurity配置:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class SegurancaConfiguracao extends WebSecurityConfigurerAdapter{
@Autowired
private UsuarioServico usuarioServico;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(this.usuarioServico).passwordEncoder(encoder());
}
public PasswordEncoder encoder() {
return new BCryptPasswordEncoder();
}
资源服务器配置:
@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class ServidorRecursoOAuthConfiguracao extends
ResourceServerConfigurerAdapter {
public void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/api/**").authenticated()
.antMatchers("/oauth2/authorization/google", "/login/oauth2/code/google", "/login").permitAll()
.antMatchers("/oauth/authorize").permitAll()
.anyRequest().permitAll()
.and()
.formLogin()
.and()
.oauth2Login()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
}