我负责我们产品的API方面。我们有几个不同的客户,从浏览器到iPad,再到Chromebook。现在,我们所有的身份验证都是直接从客户端到我们的API完成的,用户名为&密码。
我继承了一些使用OAuth进行身份验证的代码,并使用了常用的用户名/密码设置。所以在我的OwinAuthConfig
课程中,我有:
var oAuthAuthorizationOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Authenticate"),
Provider = new MyAuthorizationProvider(),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
AllowInsecureHttp = true
};
app.UseOAuthAuthorizationServer(oAuthAuthorizationOptions);
然后,通过一些黑魔法,它连接到我的MyAuthorizationProvider
类(继承OAuthAuthorizationServerProvider
),并在登录时调用方法:
public override Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{ ... }
其中context
包含重要内容(Username
和Password
),然后我可以使用这些内容对用户进行身份验证,构建其声明,创建AuthenticationTicket
和此信息然后神奇地通过访问令牌等返回给客户端。
一切都很好。
现在我有了新的要求 - 允许来自Google的第三方身份验证。在这种情况下,客户端应用程序(iOS / Android /无论如何)对Google进行身份验证,他们应该只在API端向我传递令牌(以及任何其他必需的信息)。在我这边,我需要重新验证Google令牌,并从谷歌获取所有用户信息(电子邮件,姓名等),然后我应该再将其链接到我们的用户表,建立索赔等。并将一个新令牌返回给客户端,该令牌将用于所有后续调用。
对整个OWIN管道事物有点新意,我不确定如何解决这个问题。我可以编写一个新的GoogleAuthController,它就像任何其他控制器一样,并且有一个接受Google令牌的API,并以与用户名/密码认证API相同的格式返回新令牌和其他信息。但有两件事在唠叨我:
MyAuthorizationProvider.GrantResourceOwnerCredentials()
中,我可以访问OAuthGrantResourceOwnerCredentialsContext
个对象,这样我就可以验证我的新AuthenticationTicket
。如果我在一个简单的香草控制器中这样做,我不知道如何将该票证标记为已验证。有什么线索吗?
编辑我已经看到了here所述的Google身份验证流程。我仍然对如何最好地从API方面管理流程感到困惑。客户端将获取授权代码,然后使用该身份验证代码调用API。我得到了,然后我必须通过调用Google API来获取该身份验证代码并将其转换为令牌。 (或者也许这应该是客户的责任?)无论哪种方式,我都需要使用该令牌返回到Google API并获取用户的姓名,电子邮件和头像图像,然后我需要将该电子邮件与我自己的电子邮件相匹配用于识别用户并建立其声明的数据库。然后我需要返回一个新的令牌,客户端可以使用它来连接我。
在我的问题被关闭为“太宽泛”之前,让我对我的问题更加具体:
AuthenticationProperties
的对象,还是有一些特殊的OWIN方法呢?AuthenticationTicket
标记为已验证?答案 0 :(得分:1)
从这里开始:https://developers.google.com/identity/protocols/OAuth2#basicsteps
这解释了oAuth2的工作原理。因此,您收到Google令牌,现在您致电Google并请求用户提供详细信息。您将收到足以验证他们的电子邮件。您可以存储令牌,因为它们有效一段时间,您可以继续重复使用它,直到它过期或无效为止。
在同一主题上查看此讨论:
How can I verify a Google authentication API access token?
如果您需要有关OAuth2如何运作的更多信息,我可以向您指出我自己的一篇文章:https://eidand.com/2015/03/28/authorization-system-with-owin-web-api-json-web-tokens/
有很多东西需要考虑,但听起来你需要了解这些东西是如何协同工作的。希望这会有所帮助。
答案 1 :(得分:1)
更新
我没有完全访问您的设置,但我希望以下代码可以帮助您使用Google作为ID提供商。请将以下代码添加到startup.auth.cs文件中。
var googleAuthOptions = new GoogleOAuth2AuthenticationOptions
{
ClientId = "ef4ob24ttbgmt2o8eikgg.apps.googleusercontent.com",
ClientSecret = "DAK0qzDasdfasasdfsadwerhNjb-",
Scope = { "openid", "profile", "email" },
Provider = new GoogleOAuth2AuthenticationProvider
{
OnAuthenticated = async ctx =>
{
//You can get the claims like this and add them to authentication
var tokenClaim = new Claim("GoogleAccessToken", ctx.AccessToken);
var emailClaim = new Claim("email", ctx.Email);
var claimsIdentity = new ClaimsIdentity();
claimsIdentity.AddClaim(tokenClaim);
claimsIdentity.AddClaim(emailClaim);
HttpContext.Current
.GetOwinContext()
.Authentication
.SignIn(claimsIdentity);
await Task.CompletedTask;
}
},
AuthenticationType = "Google"
};
app.UseGoogleAuthentication(googleAuthOptions);
这允许Google充当ID提供程序,并在身份验证成功时调用OnAuthenticated。您可以从中获取声明并使用它们进行登录。请告诉我这是否有效,如果没有给我更多有关您的设置的详细信息(什么样的框架,客户端设置,可能有关于您在启动文件中的设置的更多详细信息)。
谢谢。
有关我们如何使用Google作为ID提供商的详细信息,请参阅此link。我相信你可能会看到这个link,但万一你错过了它。如果这些链接都不适合您,请提供有关您偏离链接中提及的内容的具体详细信息。
我假设您的要求与这些链接中指定的要求不同。因此,我会尝试单独回答您的问题。如果您有任何其他问题,请与我们联系。
交换访问令牌的代码绝对是API的责任,因为令牌交换涉及发送ClientId和Client Secret以及代码。客户端密钥应该保存在服务器端(API)上,而不是保存在客户端上
无论客户端是通过代码还是令牌,我都需要能够在API中接收它。我应该只使用普通的vanilla接收它,端点返回一个AuthenticationProperties类型的对象,还是有一些特殊的OWIN方法呢?
如果您使用上述链接中提到的Google提供商,这应无缝运行。如果不是,则端点应该是一个匿名端点,接受代码并向Google发出请求(可以通过使用HttpClient)以获取访问令牌以及用于相关信息的配置文件对象。
如果我使用普通的香草控制器,我该如何验证我的令牌?换句话说,如何访问OWIN上下文以便我可以将AuthenticationTicket标记为已验证?
您必须将OnGrantAuthorizationCode实现为MyAuthorizationProvider类的一部分。这样就可以访问上下文,将validated设置为true。
如何编写模拟流程客户端的自动化测试? AFAICT,身份验证希望用户在物理上单击“允许”按钮以授予我的应用程序访问其身份内容的权限,然后才能生成身份验证代码。在自动化测试中,我想从代码中传递用户名/密码等。你是怎么做到的?
这可以部分实现,但是,通过该部分测试,您可以确保对您的代码进行良好的测试覆盖。因此,您必须模拟对Google API的调用,并假设您已检索到有效响应(硬编码是您从有效的手动测试中收到的响应)。现在使用有效响应测试代码的行为方式。模拟Google API cal以获得无效响应并执行相同操作。这就是我们现在测试API的方式。这假设Google API工作正常,并针对有效/无效响应测试我的代码。
谢谢你, 索马。
答案 2 :(得分:1)
所以我找到了自己的解决方案。它只是略显笨拙,不需要引用任何Google OWIN库,最重要的是,重用我的用户名/密码身份验证中的代码。
首先,我让应用程序调用与用户名/密码相同的Authenticate端点,仅使用虚拟凭据,并添加包含令牌的“GoogleToken”标头。
在我的身份验证代码中,我检查了GoogleToken标头,如果它存在,请按照该代码路径在Google服务器上进行验证,获取电子邮件地址,并链接到我自己的用户表。然后,构建声明并返回新API令牌的其余过程将遵循原始路径。
答案 3 :(得分:0)
最近经历过这样的事情后,我会尝试至少回答你的一些问题:
function onSignIn(googleUser) {
var profile = googleUser.getBasicProfile();
var idToken = googleUser.getAuthResponse().id_token;
}