如何正确获取用户的会话oauth2令牌?
我使用spring-security-oauth2-autoconfigure
实现了OAuth2授权/资源服务器。
我实现了一个客户端应用程序,该应用程序使用授权服务器登录用户并获取其访问令牌。登录阶段运行良好,因此可以获取登录数据(使用oauth2过滤器的访问令牌)。客户端应用请求中的Principal
正确显示了授权服务器填充的所有权限。
我想使用客户端应用程序作为代理,以使用请求呼叫的用户的给定访问令牌发送休息请求。
我已经尝试使用@EnableOAuth2Client
,但这不起作用。尝试自动连线时,OAuth2RestTemplate
为空。
我不得不重新实现RestTemplate
的请求范围的bean,该bean从tokenValue
获得SecurityContext
。这行得通,但我觉得这不干净。这种行为很常见,所以我应该错过一些事情。
application.yml
spring:
application.name: client
security:
oauth2:
client:
registration:
myclient:
client-id: client-id
client-secret: client-secret
redirect-uri: http://localhost:8081/login/oauth2/code/
authorization-grant-type: authorization_code
provider:
myclient:
authorization-uri: http://localhost:8090/oauth/authorize
token-uri: http://localhost:8090/oauth/token
user-info-uri: http://localhost:8090/me
user-name-attribute: name
安全配置
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http.authorizeRequests()
.antMatchers("/", "/login").permitAll()
.antMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
.and().oauth2Login()
.and().oauth2Client()
;
// @formatter:on
}
@Bean
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
@Qualifier("oauth2RestTemplate")
public RestTemplate oauth2RestTemplate() {
RestTemplate restTemplate = new RestTemplate();
restTemplate.getInterceptors().add(new ClientHttpRequestInterceptor() {
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
throws IOException {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null && auth.isAuthenticated() && auth instanceof OAuth2AuthenticationToken) {
@SuppressWarnings("unchecked")
Map<String, Object> details = (Map<String, Object>) ((OAuth2AuthenticationToken) auth).getPrincipal().getAttributes().get("details");
String tokenValue = (String) details.get("tokenValue");
if (tokenValue != null) {
request.getHeaders().add("Authorization", "Bearer " + tokenValue);
}
}
return execution.execute(request, body);
}
});
return restTemplate;
}
}
在WebController中
private @Autowired @Qualifier("oauth2RestTemplate") RestTemplate oauth2RestTemplate;
@GetMapping("/remote")
public Map<String, Object> remote() {
@SuppressWarnings("unchecked")
Map<String, Object> resp = oauth2RestTemplate.getForObject(URI.create("http://localhost:8090/api/test"), Map.class);
return resp;
}
它有效,但是我不认为自己应该配置RestTemplate
。
答案 0 :(得分:0)
不幸的是,您必须定义OAuth2RestTemplate
。但是,这是一个更干净的实现。
@Bean
public OAuth2RestTemplate oauth2RestTemplate() {
ClientCredentialsResourceDetails resourceDetails = new ClientCredentialsResourceDetails();
resourceDetails.setAccessTokenUri(format("%s/oauth/token", authServerUrl));
resourceDetails.setClientId("client_id");
resourceDetails.setClientSecret("client_secret");
resourceDetails.setGrantType("client_credentials");
resourceDetails.setScope(asList("read", "write"));
DefaultOAuth2ClientContext clientContext = new DefaultOAuth2ClientContext();
return new OAuth2RestTemplate(resourceDetails, clientContext);
}
在这种情况下,您的资源服务器将使用您自己的凭据代表您与授权服务器通信。