我试图通过Spring Boot用一个资源服务器实现OAuth2-Server。 我可以请求令牌,但是如果使用它们从资源服务器请求资源,则结果始终是“无效令牌”。
这是授权服务器配置:
@Configuration
@EnableAuthorizationServer
public class AuthserverConfiguration extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authorizationCodeServices(authorizationCodeServices())
// injects the Spring Security authentication manager (set up in WebSecurityConfiguration )
.authenticationManager(authenticationManager)
.tokenStore(tokenStore());
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
// configure security for /oauth/check_token and /oauth/token_key endpoint
security.tokenKeyAccess("permitAll()")
.checkTokenAccess("permitAll()"); // should be isAuthenticated()
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("clientId").secret("{noop}clientsecret")
.authorizedGrantTypes("authorization_code", "refresh_token", "password")
.scopes("read");
}
@Bean
public TokenStore tokenStore() {
return new InMemoryTokenStore();
}
@Bean
protected AuthorizationCodeServices authorizationCodeServices() {
// creates authorization codes, stores the codes in memory.
return new InMemoryAuthorizationCodeServices();
}
}
WebSecurityConfiguration是:
@EnableWebSecurity
@Configuration
@Order(SecurityProperties.BASIC_AUTH_ORDER - 20)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user").password("{noop}password").roles("USER");
/* for now testing with inMemoryAuthentication, later I want to use:
* auth.userDetailsService(userDetailsService); */
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.requestMatchers().antMatchers("/login", "/oauth/authorize", "/oauth/confirm_access")
.and()
.formLogin().loginPage("/login").permitAll().failureUrl("/login?error")
.and()
.authorizeRequests().anyRequest().authenticated();
}
@Bean(name = BeanIds.AUTHENTICATION_MANAGER)
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
还有UserInfoController:
@RestController
public class UserInfoController {
@RequestMapping(value = "/user")
public Principal userInfo(@AuthenticationPrincipal Principal user) {
return user;
}
}
pom.xml包含以下依赖项:+
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.0.5.RELEASE</version>
</dependency>
</dependencies>
另一方面,资源服务器是带有tomcat的标准Spring Boot项目,在端口8081上侦听GET / products(以JSON格式返回列表)。
其主类带有@EnableResourceServer
注释,其配置包含:
security:
oauth2:
resource:
user-info-uri: http://localhost:8090/user
其中8090是上述身份验证服务器的端口。
使用curl进行测试:
> curl clientId:clientsecret@localhost:8090/oauth/token -d grant_type=password -d username=user -d password=password -d scope=read`
{"access_token":"1cdd6dc2-42fe-4b55-b16d-78d189a88cc4","token_type":"bearer","refresh_token":"d59d78b5-43c8-4d12-b4ee-007da8548744","expires_in":43199,"scope":"read"}
> curl -H 'Authorization: Bearer 1cdd6dc2-42fe-4b55-b16d-78d189a88cc4' 'localhost:8090/oauth/check_token?token=1cdd6dc2-42fe-4b55-b16d-78d189a88cc4'
{"exp":1561956415,"user_name":"user","authorities":["ROLE_USER"],"client_id":"clientId","scope":["read"]}+ set +o xtrace
令牌似乎是有效且可以识别的(如果我篡改令牌,则会收到另一个错误:“无法识别的令牌”)。
但是,如果我尝试使用令牌从资源服务器请求数据:
> curl -H 'Authorization: Bearer 1cdd6dc2-42fe-4b55-b16d-78d189a88cc4' localhost:8081/products
{"error":"invalid_token","error_description":"Invalid access token: 1cdd6dc2-42fe-4b55-b16d-78d189a88cc4"}
此错误非常一致,我尝试了许多不同的配置更改,甚至添加了TokenServices,UserDetailsService等的自定义实现。
每次通过curl执行请求时,在调试日志中,我都会在资源服务器的输出中找到以下行:
Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@2b139cc0: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS
这使我感到困惑,因为在我的理解中,主体不应该是匿名用户。
如何解决此问题并从资源服务器请求数据?任何帮助表示高度赞赏。