我已经到了这一点,我可以成功地向google终端发出授权请求
https://accounts.google.com/o/oauth2/auth
并且Google询问用户是否允许我的应用访问其帐户.到目前为止都不错当用户点击“确定”后,Google会按预期的方式调用回调URL.
问题是当我在OAuthWebSecurity类(Microsoft.Web.WebPages.OAuth)上调用VerifyAuthentication方法时,
var authenticationResult = OAuthWebSecurity.VerifyAuthentication(Url.Action("ExternalLoginCallback",new { ReturnUrl = returnUrl }));
它总是返回一个AuthenticationResult与IsSuccessful = false和Provider =“”
我已经查看了这个代码,OAuthWebSecurity类尝试从中获取提供者名称
Request.QueryString["__provider__"]
但是Google并没有在查询字符串中发送此信息.我已经实施的另一个提供商(LinkedIn)正在发送提供商名称,它一切正常.
我不知道我可以做什么,除了放弃Microsoft.Web.WebPages.OAuth类,只是使用DotNetOpenAuth没有他们,但我希望有人可能有另一个解决方案,我可以尝试…
我已经广泛搜索,但似乎找不到任何帮助…我发现真的很难,只是找到人做同样的事情的例子,这真的让我感到惊讶.
任何帮助非常感谢!
解决方法
他说:
针对ASP.Net MVC 4的DNOA和OAuthWebSecurity仅提供给Google的OpenId提供程序.这是一个您可以使用的OAuth2客户端.
重要 – 如果您使用ASP.Net MVC 5,此包不适用.您应该使用Microsoft.Owin.Security.Google. (它也附带VS 2013中的MVC 5启动器模板)
最后我得到了这个结果,通过捕获请求进来,并做我自己的检查,看看它是哪个提供者. Google允许您将参数发送到名为“state”的OAuth请求,当它们进行回调时,它们将直接传递给您,因此我使用此参数传递google的提供程序名称,并且我检查没有“__provider__”.
这样的:
public String GetProviderNameFromQueryString(NameValueCollection queryString) { var result = queryString["__provider__"]; if (String.IsNullOrWhiteSpace(result)) { result = queryString["state"]; } return result; }
然后,我为Google实现了一个自定义的OAuth2Client,我自己手动调用VerifyAuthentication方法,绕过了Microsoft的包装器.
if (provider is GoogleCustomClient) { authenticationResult = ((GoogleCustomClient)provider).VerifyAuthentication(context,new Uri(String.Format("{0}/oauth/ExternalLoginCallback",context.Request.Url.GetLeftPart(UriPartial.Authority).ToString()))); } else { authenticationResult = OAuthWebSecurity.VerifyAuthentication(returnUrl); }
这使我能够保留我已经为其他提供商使用Microsoft包装器的东西.
根据@ 1010100 1001010的要求,这里是我自定义的OAuth2Client for Google(注意:需要一些TIDYING!我没有办法处理代码上升,它的工作虽然):
public class GoogleCustomClient : OAuth2Client { ILogger _logger; #region Constants and Fields /// <summary> /// The authorization endpoint. /// </summary> private const string AuthorizationEndpoint = "https://accounts.google.com/o/oauth2/auth"; /// <summary> /// The token endpoint. /// </summary> private const string TokenEndpoint = "https://accounts.google.com/o/oauth2/token"; /// <summary> /// The _app id. /// </summary> private readonly string _clientId; /// <summary> /// The _app secret. /// </summary> private readonly string _clientSecret; #endregion public GoogleCustomClient(string clientId,string clientSecret) : base("Google") { if (string.IsNullOrWhiteSpace(clientId)) throw new ArgumentNullException("clientId"); if (string.IsNullOrWhiteSpace(clientSecret)) throw new ArgumentNullException("clientSecret"); _logger = ObjectFactory.GetInstance<ILogger>(); this._clientId = clientId; this._clientSecret = clientSecret; } protected override Uri GetServiceLoginUrl(Uri returnUrl) { StringBuilder serviceUrl = new StringBuilder(); serviceUrl.AppendFormat("{0}?scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile",AuthorizationEndpoint); serviceUrl.Append("&state=google"); serviceUrl.AppendFormat("&redirect_uri={0}",returnUrl.ToString()); serviceUrl.Append("&response_type=code"); serviceUrl.AppendFormat("&client_id={0}",_clientId); return new Uri(serviceUrl.ToString()); } protected override IDictionary<string,string> GetUserData(string accessToken) { RestClient client = new RestClient("https://www.googleapis.com"); var request = new RestRequest(String.Format("/oauth2/v1/userinfo?access_token={0}",accessToken),Method.GET); IDictionary<String,String> extraData = new Dictionary<String,String>(); var response = client.Execute(request); if (null != response.ErrorException) { return null; } else { try { var json = JObject.Parse(response.Content); string firstName = (string)json["given_name"]; string lastName = (string)json["family_name"]; string emailAddress = (string)json["email"]; string id = (string)json["id"]; extraData = new Dictionary<String,String> { {"accesstoken",accessToken},{"name",String.Format("{0} {1}",firstName,lastName)},{"firstname",firstName},{"lastname",lastName},{"email",emailAddress},{"id",id} }; } catch(Exception ex) { _logger.Error("Error requesting OAuth user data from Google",ex); return null; } return extraData; } } protected override string QueryAccessToken(Uri returnUrl,string authorizationCode) { StringBuilder postData = new StringBuilder(); postData.AppendFormat("client_id={0}",this._clientId); postData.AppendFormat("&redirect_uri={0}",HttpUtility.UrlEncode(returnUrl.ToString())); postData.AppendFormat("&client_secret={0}",this._clientSecret); postData.AppendFormat("&grant_type={0}","authorization_code"); postData.AppendFormat("&code={0}",authorizationCode); string response = ""; string accessToken = ""; var webRequest = (HttpWebRequest)WebRequest.Create(TokenEndpoint); webRequest.Method = "POST"; webRequest.ContentType = "application/x-www-form-urlencoded"; try { using (Stream s = webRequest.GetRequestStream()) { using (StreamWriter sw = new StreamWriter(s)) sw.Write(postData.ToString()); } using (WebResponse webResponse = webRequest.GetResponse()) { using (StreamReader reader = new StreamReader(webResponse.GetResponseStream())) { response = reader.ReadToEnd(); } } var json = JObject.Parse(response); accessToken = (string)json["access_token"]; } catch(Exception ex) { _logger.Error("Error requesting OAuth access token from Google",ex); return null; } return accessToken; } public override AuthenticationResult VerifyAuthentication(HttpContextBase context,Uri returnPageUrl) { string code = context.Request.QueryString["code"]; if (string.IsNullOrEmpty(code)) { return AuthenticationResult.Failed; } string accessToken = this.QueryAccessToken(returnPageUrl,code); if (accessToken == null) { return AuthenticationResult.Failed; } IDictionary<string,string> userData = this.GetUserData(accessToken); if (userData == null) { return AuthenticationResult.Failed; } string id = userData["id"]; string name; // Some oAuth providers do not return value for the 'username' attribute. // In that case,try the 'name' attribute. If it's still unavailable,fall back to 'id' if (!userData.TryGetValue("username",out name) && !userData.TryGetValue("name",out name)) { name = id; } // add the access token to the user data dictionary just in case page developers want to use it userData["accesstoken"] = accessToken; return new AuthenticationResult( isSuccessful: true,provider: this.ProviderName,providerUserId: id,userName: name,extraData: userData); }