gpt4 book ai didi

asp.net-mvc-4 - OAuth2 和 DotNetOpenAuth - 实现 Google 自定义客户端

转载 作者:行者123 更新时间:2023-12-02 20:29:46 24 4
gpt4 key购买 nike

我在使用 DotNetOpenAuth 和 MVC4 为 Google 实现自定义 OAuth2Client 时遇到问题。

我已经可以成功向 Google 端点发出授权请求了 https://accounts.google.com/o/oauth2/auth

Google 会询问用户是否允许我的应用程序访问他们的帐户。到目前为止一切都很好。当用户点击“确定”时,Google 就会按预期调用我的回调网址。

问题是当我在 OAuthWebSecurity 类 (Microsoft.Web.WebPages.OAuth) 上调用 verifyAuthentication 方法时

var authenticationResult = OAuthWebSecurity.VerifyAuthentication(Url.Action("ExternalLoginCallback", new { ReturnUrl = returnUrl }));

它始终返回带有 IsSuccessful = falseProvider = "" 的 AuthenticationResult

我已经研究了这方面的代码,OAuthWebSecurity 类尝试从

获取提供程序名称
Request.QueryString["__provider__"]

但 Google 不会在查询字符串中发送回此信息。我实现的另一个提供商(LinkedIn)正在发送回提供商名称,一切正常。

我不确定从这一点上我能做什么,除了放弃 Microsoft.Web.WebPages.OAuth 类并在没有它们的情况下只使用 DotNetOpenAuth 之外,但我希望有人可能有另一个我可以尝试的解决方案...

我进行了广泛的搜索,但似乎找不到任何帮助......我发现即使只是找到人们做同样事情的例子也非常困难,这真的让我感到惊讶。

非常感谢任何帮助!

最佳答案

更新:正如 Matt Johnson 在下面提到的,他已经打包了一个解决方案,您可以从 GitHub 获取:https://github.com/mj1856/DotNetOpenAuth.GoogleOAuth2

正如他所指出的: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的要求,这是我为Google定制的OAuth2Client(注意:它需要一些整理!我还没有来得及整理代码。不过它确实有效):

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);
}

关于asp.net-mvc-4 - OAuth2 和 DotNetOpenAuth - 实现 Google 自定义客户端,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13727466/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com