我已经到了这一点,我可以成功地向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);
- }