[英]Spring Oauth2 login - anonymous not allowed?
遵循手冊,我實現了連接到Facebook graph API並從用戶檢索信息的目的。 當我想使用Facebook授予訪問權限(登錄)時,出現了此錯誤:
org.springframework.security.authentication.InsufficientAuthenticationException: Authentication is required to obtain an access token (anonymous not allowed)
at org.springframework.security.oauth2.client.token.AccessTokenProviderChain.obtainAccessToken(AccessTokenProviderChain.java:88) ~[spring-security-oauth2-2.0.7.RELEASE.jar:na]
at org.springframework.security.oauth2.client.OAuth2RestTemplate.acquireAccessToken(OAuth2RestTemplate.java:221) ~[spring-security-oauth2-2.0.7.RELEASE.jar:na]
at org.springframework.security.oauth2.client.OAuth2RestTemplate.getAccessToken(OAuth2RestTemplate.java:173) ~[spring-security-oauth2-2.0.7.RELEASE.jar:na]
at org.springframework.security.oauth2.client.OAuth2RestTemplate.createRequest(OAuth2RestTemplate.java:105) ~[spring-security-oauth2-2.0.7.RELEASE.jar:na]
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:565) ~[spring-web-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.security.oauth2.client.OAuth2RestTemplate.doExecute(OAuth2RestTemplate.java:128) ~[spring-security-oauth2-2.0.7.RELEASE.jar:na]
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:530) ~[spring-web-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.web.client.RestTemplate.getForObject(RestTemplate.java:237) ~[spring-web-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_25]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_25]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_25]
at java.lang.reflect.Method.invoke(Method.java:483) ~[na:1.8.0_25]
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317) ~[spring-aop-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190) ~[spring-aop-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) ~[spring-aop-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:133) ~[spring-aop-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:121) ~[spring-aop-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207) ~[spring-aop-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at com.sun.proxy.$Proxy79.getForObject(Unknown Source) ~[na:na]
at com.xxxx.xxxx.controllers.FacebookController.login(FacebookController.java:39) ~[classes/:na]
該錯誤明確指出“不允許匿名用戶獲取訪問令牌”。 當然,用戶是匿名的,並且正在嘗試進行身份驗證。 那我該怎么辦呢? 也許我在控制器上執行的操作不是正確的登錄方式?
控制器:
@RequestMapping("/facebookLogin")
@ResponseBody
public User login() {
ObjectNode result = facebookRestTemplate
.getForObject(
"https://graph.facebook.com/me/?fields=name,email,third_party_id",
ObjectNode.class);
...
}
我正在使用spring-security:4.0.1.RELEASE
和spring-security-oauth2:2.0.7.RELEASE
注意:在這種情況下,我使用Facebook,但該問題也應出現在Google,Twitter等上。
您共享的代碼段不顯示登錄信息,僅在您嘗試檢索有關用戶的信息時顯示。
根據Spring文檔,您需要對其進行調整以使其能夠與FB一起使用。
一些外部OAuth2提供程序(例如Facebook)不能完全正確地實現該規范,否則它們只是停留在比Spring Security OAuth更舊的規范版本上。 要在客戶端應用程序中使用這些提供程序,您可能需要調整客戶端基礎結構的各個部分。
以Facebook為例,在tonr2應用程序中有一個Facebook功能(您需要更改配置以添加自己的,有效的客戶ID和密碼-它們很容易在Facebook網站上生成)。
在JSP(tomcat)的Servlet頁面Facebook Connect示例中,對另一個線程的響應是關於如何執行此操作的
這是有關如何在MVC實現中執行此操作的另一個解決方案的副本:
public ActionResult Authenticate()
{
var oauthFacebook = new FacebookOAuth();
if (Request["code"] == null)
{
//Redirect the user to Facebook for authorization.
Response.Redirect(oauthFacebook.AuthorizationLinkGet());
}
else
{
//Get the access token and secret.
oauthFacebook.AccessTokenGet(Request["code"]);
if (oauthFacebook.Token.Length > 0)
{
//We can now make our api calls
var user = oauthFacebook.GetAttributes();
}
}
}
public class FacebookOAuth : Oauth
{
public FacebookOAuth()
{
Authorize = "https://graph.facebook.com/oauth/authorize";
AccessToken = "https://graph.facebook.com/oauth/access_token";
CallbackUrl = "http://<YourURLHere>/Authenticate";
AttributesBaseUrl = "https://graph.facebook.com/me/?access_token=";
ConsumerKey = ConfigurationManager.AppSettings["FacebookConsumerKey"];//Ur Consumer Key goes here
ConsumerSecret = ConfigurationManager.AppSettings["FacebookConsumerSecret"];//Ur Consumer secret goes here
Provider = "Facebook";
}
public override string AuthorizationLinkGet()
{
return
string.Format(
"{0}?client_id={1}&redirect_uri={2}&scope=email,user_education_history,user_location,user_hometown",
Authorize, ConsumerKey, CallbackUrl);
}
public User GetAttributes()
{
string attributesUrl = string.Format("{0}{1}", AttributesBaseUrl, Token);
string attributes = WebRequest(Method.Get, attributesUrl, String.Empty);
var FacebookUser = new JavaScriptSerializer().Deserialize<FacebookUser>(attributes);
return new User()
{
FirstName = FacebookUser.first_name,
MiddleName = FacebookUser.middle_name,
LastName = FacebookUser.last_name,
Locale = FacebookUser.locale,
UserEmail = FacebookUser.email,
AuthProvider = Provider,
AuthToken=Token
};
}
}
public abstract class Oauth
{
#region Method enum
public enum Method
{
Get,
Post,
Delete
} ;
#endregion
protected string AccessToken;
protected string AttributesBaseUrl;
protected string Authorize;
protected string CallbackUrl;
protected string ConsumerKey;
protected string ConsumerSecret;
public string Provider { get; protected set; }
public string Token { get; set; }
public virtual string AuthorizationLinkGet()
{
return
string.Format(
"{0}?client_id={1}&redirect_uri={2}&scope=publish_stream,email,user_education_history,user_location",
Authorize, ConsumerKey, CallbackUrl);
}
public void AccessTokenGet(string authToken)
{
Token = authToken;
string accessTokenUrl = string.Format("{0}?client_id={1}&redirect_uri={2}&client_secret={3}&code={4}",
AccessToken, ConsumerKey, CallbackUrl, ConsumerSecret, authToken);
string response = WebRequest(Method.Get, accessTokenUrl, String.Empty);
if (response.Length > 0)
{
//Store the returned access_token
NameValueCollection qs = HttpUtility.ParseQueryString(response);
if (qs["access_token"] != null)
{
Token = qs["access_token"];
}
}
}
public string WebRequest(Method method, string url, string postData)
{
StreamWriter requestWriter;
string responseData = string.Empty;
var webRequest = System.Net.WebRequest.Create(url) as HttpWebRequest;
if (webRequest != null)
{
webRequest.Method = method.ToString();
webRequest.ServicePoint.Expect100Continue = false;
webRequest.Timeout = 20000;
if (method == Method.Post)
{
webRequest.ContentType = "application/x-www-form-urlencoded";
//POST the data.
requestWriter = new StreamWriter(webRequest.GetRequestStream());
try
{
requestWriter.Write(postData);
}
finally
{
requestWriter.Close();
}
}
responseData = WebResponseGet(webRequest);
}
return responseData;
}
public string WebResponseGet(HttpWebRequest webRequest)
{
StreamReader responseReader = null;
string responseData;
try
{
responseReader = new StreamReader(webRequest.GetResponse().GetResponseStream());
responseData = responseReader.ReadToEnd();
}
finally
{
if (webRequest != null) webRequest.GetResponse().GetResponseStream().Close();
if (responseReader != null) responseReader.Close();
}
return responseData;
}
}
希望能幫助到你!
嗨,在tonr2項目中檢查此代碼
@Bean
public OAuth2ProtectedResourceDetails facebook() {
AuthorizationCodeResourceDetails details = new AuthorizationCodeResourceDetails();
details.setId("facebook");
details.setClientId("233668646673605");
details.setClientSecret("33b17e044ee6a4fa383f46ec6e28ea1d");
details.setAccessTokenUri("https://graph.facebook.com/oauth/access_token");
details.setUserAuthorizationUri("https://www.facebook.com/dialog/oauth");
details.setTokenName("oauth_token");
details.setAuthenticationScheme(AuthenticationScheme.query);
details.setClientAuthenticationScheme(AuthenticationScheme.form);
return details;
}
在OAuth2ProtectedResourceDetails上相應地添加Facebook憑據。 然后,當您嘗試從facebook獲取數據時,Spring Security OAuth AuthenticationProvider將引用此bean,一旦FacebookController嘗試訪問FB數據,該數據就會自動檢測到。 但是您必須了解以下配置:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("marissa").password("wombat").roles("USER").and().withUser("sam")
.password("kangaroo").roles("USER");
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/resources/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http.authorizeRequests()
.antMatchers("/sparklr/**","/facebook/**").hasRole("USER")
.anyRequest().permitAll()
.and()
.logout()
.logoutSuccessUrl("/login.jsp")
.permitAll()
.and()
.formLogin()
.loginProcessingUrl("/login")
.loginPage("/login.jsp")
.failureUrl("/login.jsp?authentication_error=true")
.permitAll();
// @formatter:on
}
}
可以說您將使用tonr2應用程序,inMemoryAuthentication使用用戶“ marissa”和密碼“ wombat”對Spring安全性進行身份驗證。 因此,在您的用戶界面中,嘗試首先針對Spring Security進行身份驗證。 身份驗證后,您將擁有“ USER”角色。 只有這次,您才可以訪問名為FaceBookController的資源,該資源嘗試從facebook本身檢索數據,請參考此代碼段,
http.authorizeRequests()
.antMatchers("/sparklr/**","/facebook/**").hasRole("USER")
.anyRequest().permitAll()
.and()
因此,只需相應地調整代碼即可。
UPDATE
請注意:給定的Spring Security示例應用程序尚未配置為具有動態客戶端密鑰,它仍使用OAuth2ProtectedResourceDetails中的單個密鑰進行了硬編碼,只是為了簡單地演示它。 從經過身份驗證的Facebook用戶中動態獲取Facebook客戶端密鑰需要其他更多步驟。 或者,如果您只想測試Facebook檢索,則將上面的代碼調整為類似這樣的代碼,
http.authorizeRequests()
.anyRequest().permitAll()
.and()
消除要求用戶具有USER角色的限制,只允許所有請求而無需首先在Spring Security上進行身份驗證。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.