我一直在過去的幾天中使用spring-security-oauth2來實現spring引導/ spring安全性和java配置。我已經設法解決了大部分的困難,但是現在出現了什麼問題,我很難過。Spring-Oauth2訪問令牌請求永遠不會成功,因爲缺少CSRF'保留狀態'
我成功地完成以下步驟:
- 發送用戶的供應商授權以代表他們的應用
- 提示用戶按安全
- 用戶授權來登錄到供應商應用程序和重定向url將它們發送回原始url處的客戶端應用程序以及查詢字符串中的
?code=asdfa&state=asdfasf
在此點,我相信任何使用AuthorizationCodeResourceDetails
應該交換訪問令牌的授權代碼和客戶端應用程序憑證。這是下一個堆棧跟蹤過程失敗的地方。在客戶端的樣子
Caused by: org.springframework.security.oauth2.common.exceptions.InvalidRequestException: Possible CSRF detected - state parameter was present but no state could be found
at org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeAccessTokenProvider.getParametersForTokenRequest(AuthorizationCodeAccessTokenProvider.java:246)
at org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeAccessTokenProvider.obtainAccessToken(AuthorizationCodeAccessTokenProvider.java:198)
at org.springframework.security.oauth2.client.token.AccessTokenProviderChain.obtainNewAccessTokenInternal(AccessTokenProviderChain.java:142)
at org.springframework.security.oauth2.client.token.AccessTokenProviderChain.obtainAccessToken(AccessTokenProviderChain.java:118)
at org.springframework.security.oauth2.client.OAuth2RestTemplate.acquireAccessToken(OAuth2RestTemplate.java:221)
at org.springframework.security.oauth2.client.OAuth2RestTemplate.getAccessToken(OAuth2RestTemplate.java:173)
at org.springframework.security.oauth2.client.OAuth2RestTemplate.createRequest(OAuth2RestTemplate.java:105)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:564)
at org.springframework.security.oauth2.client.OAuth2RestTemplate.doExecute(OAuth2RestTemplate.java:128)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:529)
at org.springframework.web.client.RestTemplate.getForEntity(RestTemplate.java:261)
at com.pvr.apps.admin.user.UserServiceImpl.getAllUsers(UserServiceImpl.java:51)
at com.pvr.apps.admin.web.IndexController.serveUserList(IndexController.java:35)
事(我也有在主配置的@EnableOAuth2Client
註釋)。
@Component
public class UserServiceImpl implements UserService {
@Resource
@Qualifier("accessTokenRequest")
private AccessTokenRequest accessTokenRequest;
public OAuth2ProtectedResourceDetails createResource() {
AuthorizationCodeResourceDetails resourceDetails = new AuthorizationCodeResourceDetails();
resourceDetails.setScope(Lists.newArrayList("read", "write"));
resourceDetails.setClientId("admin");
resourceDetails.setClientSecret("password");
resourceDetails.setAuthenticationScheme(AuthenticationScheme.query);
resourceDetails.setAccessTokenUri("http://provider.com:8080/oauth/token");
resourceDetails.setUserAuthorizationUri("http://provider.com:8080/oauth/authorize");
return resourceDetails;
}
@Override
public List<User> getAllUsers() {
RestTemplate template = new OAuth2RestTemplate(createResource(), new DefaultOAuth2ClientContext(accessTokenRequest));
ResponseEntity<User[]> responseEntity = template.getForEntity("http://provider.com:8080/users/", User[].class);
return Lists.newArrayList(responseEntity.getBody());
}
}
而且對事物的提供方:
授權服務器配置:
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter{
@Autowired
private LoginUrlAuthenticationEntryPoint authenticationEntryPoint;
@Autowired
private AuthenticationManager authenticationManager;
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer
.authenticationEntryPoint(authenticationEntryPoint)
.tokenKeyAccess("isAnonymous() || hasAuthority('ROLE_TRUSTED_CLIENT')")
.checkTokenAccess("hasAuthority('ROLE_TRUSTED_CLIENT')");
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
endpoints
.authenticationManager(authenticationManager)
.accessTokenConverter(converter)
.tokenStore(new JwtTokenStore(converter));
}
// TODO: this should read from a db
public void configure(ClientDetailsServiceConfigurer clientConfigurer) throws Exception {
clientConfigurer.inMemory()
.withClient("admin").secret("password")
.authorizedGrantTypes(
GrantType.PASSWORD.type,
GrantType.AUTHORIZATION_CODE.type,
GrantType.IMPLICIT.type,
GrantType.REFRESH_TOKEN.type
)
.authorities("ROLE_TRUSTED_CLIENT")
.scopes("read", "write", "trust")
.accessTokenValiditySeconds(60);
}
}
和資源服務器配置:
@Configuration
@EnableWebMvcSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
UserDetailsService userDetailService;
@Autowired
AuthenticationProvider authenticationProvider;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginProcessingUrl("/login.do")
.usernameParameter("uid")
.passwordParameter("pwd")
.loginPage("/login")
.failureUrl("/login?error=true")
.and()
.userDetailsService(userDetailService);
}
}
另外,我打算在我理解了所有這些之後再做一次寫作。目前的文檔和示例很稀疏,在較早的解決方法和較新的便利性之間有些混亂。 @Rob絞盤? – RutledgePaulV
我也有同樣的錯誤,但我正在使用三個應用程序實現OAuth2 Authorize,資源和客戶端服務器都在不同的端口上運行,它將在您的同一個URL上結束。 –
嗨@Paul_R你可以分享你寫的auth代碼嗎?你的代碼結構與我偶然發現的其他例子截然不同,它會非常有幫助。 –