[英]Spring Security OAuth2- POST request to oauth/token redirects to login and role displays ROLE_ANONYMOUS
我正在跟蹤鏈接https://spring.io/blog/2015/02/03/sso-with-oauth2-angular-js-and-spring-security-part-v和github項目https:// github。 com / spring-guides / tut-spring-security-and-angular-js / tree / master / oauth2 。 我能夠登錄到OAuth提供程序,並在客戶端中重新獲得授權代碼。
現在,我從客戶端發出以下調用,以從提供程序獲取令牌(提供程序位於端口9999上)
HttpHeaders headers = new HttpHeaders();
headers.add("Accept",MediaType.APPLICATION_JSON_VALUE);
List<String> cookies = httpEntity.getHeaders().get("Cookie");
headers.put("Cookie", cookies);
String redirectURL= "http://localhost:9999/oauthprovider/oauth/token" + "?" + "response_type=token" + "&" + "grant_type=authorization_code" + "&" + "client_id=acme"+ "&" + "client_secret=acmesecret"+ "&" + "redirect_uri=http://localhost:8081/callback"+"&" + "code=" + authCode + "&" + "state=" + stateValue;
HttpEntity<String> redirectResponse = template.exchange(
redirectURL,
HttpMethod.POST,
responseentity,
String.class);
result=redirectResponse.toString()
結果變量值具有以下內容(盡管不建議使用,但我已禁用了csrf並已將client_secret作為查詢參數發送(暫時))
<302 Found,{X-Content-Type-Options=[nosniff], X-XSS-Protection=[1; mode=block], Cache-Control=[no-cache, no-store, max-age=0, must-revalidate], Pragma=[no-cache], Expires=[0], X-Frame-Options=[DENY], Location=[http://localhost:9999/oauthprovider/oauthlogin], Content-Length=[0], Date=[Thu, 09 Nov 2017 12:07:37 GMT]}>
在控制台中,我有這些
Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@9055c2bc: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: 2B669DF59BCE8047849BFBCA148BEE67; Granted Authorities: ROLE_ANONYMOUS
由於角色是ROLE_ANONYMOUS,我是否要重定向回登錄(如上所述,我正在日志中獲取登錄名)? 我該如何解決該問題?
添加有關代碼的更多詳細信息(僅對鏈接中提供的示例代碼進行了少量更改)。 提供者的上下文路徑為/ oauthprovider,通過curl調用,我得到了令牌。
@Configuration
@EnableAuthorizationServer
protected static class OAuth2AuthorizationConfig extends
AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
//................................
//................................
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("acme")
.secret("acmesecret")
.authorizedGrantTypes("authorization_code", "refresh_token",
"password").scopes("openid").autoApprove(true).redirectUris("http://localhost:8081/callback");
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
throws Exception {
endpoints.authenticationManager(authenticationManager).accessTokenConverter(
jwtAccessTokenConverter());
}
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer)
throws Exception {
oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess(
"isAuthenticated()");
}
}
@Configuration
@Order(-20)
protected static class LoginConfig extends WebSecurityConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.formLogin().loginPage("/oauthlogin").loginProcessingUrl("/login").failureUrl("/login?error=true").permitAll()
.and()
.requestMatchers().antMatchers("/login", "/oauthlogin", "/oauth/authorize", "/oauth/token" ,"/oauth/confirm_access")
.and()
.authorizeRequests().anyRequest().authenticated();
// @formatter:on
http.csrf().disable();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.parentAuthenticationManager(authenticationManager);
}
}
調用令牌端點你需要發送的Authorization
標頭值base64(client_id:client_secret)
和身體,你應該發送username
, password
, grant_type
為FORM_URLENCODED
:
String oauthHost = InetAddress.getByName(OAUTH_HOST).getHostAddress();
HttpHeaders headers = new HttpHeaders();
RestTemplate restTemplate = new RestTemplate();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
// Basic Auth
String plainCreds = clientId + ":" + clientSecret;
byte[] plainCredsBytes = plainCreds.getBytes();
byte[] base64CredsBytes = org.apache.commons.net.util.Base64.encodeBase64(plainCredsBytes);
String base64Creds = new String(base64CredsBytes);
headers.add("Authorization", "Basic " + base64Creds);
// params
map.add("username", username);
map.add("password", password);
map.add("grant_type", GRANT_TYPE);
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<MultiValueMap<String, String>>(map,
headers);
// CALLING TOKEN URL
OauthTokenRespone res = null;
try {
res = restTemplate.postForObject(OAUTH_TOKEN_URL.replace(OAUTH_HOST, oauthHost), request,
OauthTokenRespone.class);
} catch (Exception ex) {
ex.printStackTrace();
}
}
@JsonIgnoreProperties(ignoreUnknown = true)
public class OauthTokenRespone {
private String access_token;
private String token_type;
private String refresh_token;
private String expires_in;
private String scope;
private String organization;
//getter and setter
}
我最后一天的測試出了點問題。 如果我的處理程序在客戶端或提供程序中,我可以獲取訪問令牌。 如果我的重定向處理程序在提供程序中,則根據調試日志,用戶不是匿名的(可能是由於會話..?),但看起來我必須始終使用一個redirect_url。(否則,我會收到redirect_uri不匹配錯誤。)
以下是獲得json響應的工作代碼。
@ResponseBody
@RequestMapping(value = "/clientcallback", method = RequestMethod.GET)
public ResponseEntity<OauthTokenResponse> redirectCallback(@RequestParam (value= "code", defaultValue="") String authCode,@RequestParam (value= "state", defaultValue="") String stateValue,HttpEntity<String> httpEntity)
{
HttpHeaders headers = new HttpHeaders();
RestTemplate restTemplate = new RestTemplate();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
String plainCreds = "acme:acmesecret";
byte[] plainCredsBytes = plainCreds.getBytes();
byte[] base64CredsBytes = org.apache.commons.net.util.Base64.encodeBase64(plainCredsBytes);
String base64Creds = new String(base64CredsBytes);
headers.add("Authorization", "Basic " + base64Creds);
List<String> cookies = httpEntity.getHeaders().get("Cookie");
if(cookies != null)
{
headers.put("Cookie", cookies);
}
else
{
cookies = httpEntity.getHeaders().get("Set-Cookie");
headers.put("Set-Cookie", cookies);
}
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<MultiValueMap<String, String>>(map,
headers);
OauthTokenResponse res = null;
try {
res = restTemplate.postForObject("http://localhost:9999/uaa/oauth/token?grant_type=authorization_code&client_id=acme&redirect_uri=http://localhost:8081/clientcallback&code=" + authCode, request,
OauthTokenResponse.class);
} catch (Exception ex) {
ex.printStackTrace();
}
return new ResponseEntity<OauthTokenResponse>(res, HttpStatus.OK);
}
再次感謝您的提示。
我知道這很舊,但是最近遇到了一個非常相似的問題,因此我發布了解決方案。
我以Simle SSO示例為基礎進行修改。 我正在使用映射到/
(web root)的spring安全過濾器和使用映射到/auth/*
端點的spring oauth。 當我嘗試訪問/auth/oauth/token
我將重定向到登錄頁面。 經過一些調試后,我找出了原因:
通過使用@EnableAuthorizationServer
您將導入AuthorizationServerSecurityConfiguration
,該配置可保護端點/oauth/token
, /oauth/token_key
和/oauth/check_token
。 只要您的授權服務器映射到Web根目錄,一切都將使用此默認配置。 在我的情況下,對/auth/oauth/token
請求只是重定向到登錄頁面,因為spring安全無法找到該路徑的規則。
我的解決方案是在我的spring安全配置中使用/auth
前綴手動保護那些端點。
希望這可以幫助。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.