如何管理 API 对 Google 的侧授权?
How to manage API side authorization for Google?
我负责我们产品的 API 方面。我们有几种不同的客户端,从浏览器到 iPad 再到 Chromebook。现在,我们所有的身份验证都是直接从客户端到我们的 API,使用用户名和密码。
我继承了一些使用 OAuth 进行身份验证的代码,使用通常的 username/password 设置。所以在我的 OwinAuthConfig
class 里面,我有:
var oAuthAuthorizationOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Authenticate"),
Provider = new MyAuthorizationProvider(),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
AllowInsecureHttp = true
};
app.UseOAuthAuthorizationServer(oAuthAuthorizationOptions);
然后,通过一些黑魔法,它连接到我的 MyAuthorizationProvider
class(它继承了 OAuthAuthorizationServerProvider
),并在登录时调用方法:
public override Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{ ... }
其中 context
包含重要的内容(Username
和 Password
),然后我可以使用它们来验证用户、建立他的声明、创建 AuthenticationTicket
和然后,此信息会神奇地 return 通过访问令牌等
发送到客户端
一切都很好。
现在我有一个新要求 - 允许来自 Google 的第 3 方身份验证。在这种情况下,客户端应用程序 (iOS/Android/whatever) 使用 Google 进行身份验证,他们应该在 API 端将令牌(和任何其他所需信息)传递给我。在我这边,然后我需要重新验证 Google 令牌,并从 Google 获取所有用户信息(电子邮件、姓名等),然后我应该再次从中获取 link给我们的用户table,建立声明等,并return给客户端一个新的令牌,它将在所有后续调用中使用。
作为整个 OWIN 管道的新手,我不确定具体如何去做。我可以写一个新的 GoogleAuthController,它就像任何其他控制器一样,并且有一个 API 接受 Google 令牌,returns 新令牌和其他信息格式与 username/password 身份验证 API 相同。但是有两件事在困扰着我:
- 我有一种尴尬的感觉,就像这是新手做事的方式,重新发明轮子,而且真的有一种超酷的神奇方式可以将东西连接在一起,我宁愿使用它;和
- 在
MyAuthorizationProvider.GrantResourceOwnerCredentials()
中,我可以访问 OAuthGrantResourceOwnerCredentialsContext
对象,这使我可以验证我的新 AuthenticationTicket
。如果我在普通控制器中执行此操作,我不知道如何将该票证标记为已验证。
有什么线索吗?
编辑 我已经看到 Google 身份验证流程,如 here 所述。我仍然对如何最好地从 API 端管理流程感到困惑。客户端将获取授权代码,然后使用该授权代码调用 API。我明白了,然后我必须获取该授权代码并通过调用 Google API 将其转换为令牌。 (或者这应该是客户的责任?)无论哪种方式,我都需要使用该令牌返回到 Google API 并获取用户的姓名、电子邮件和头像图像,然后我需要将该电子邮件与我自己的数据库进行匹配,以识别用户并建立他们的声明。然后我需要 return 一个新的令牌,客户端可以使用它来连接到我。
让我更具体地说明我的问题,在我的问题结束之前 "too broad":
- 当客户端完成 Google API 的身份验证后,它会返回一个 "code"。该代码仍然需要转换为令牌。那应该由谁负责——客户还是API? (如果只是为了更好地分配工作量,我倾向于将其作为客户的责任。)
- 不管客户端传过来的是code还是token,我都需要能够在API中接收到。我应该只使用一个普通的香草控制器来接收它,端点 returning 一个类型
AuthenticationProperties
的对象,还是有一些特殊的 OWIN 方法来接收它?
- 如果我使用的是普通控制器,我该如何验证我的令牌?换句话说,如何访问 OWIN 上下文以便我可以将
AuthenticationTicket
标记为已验证?
- 如何编写模拟流程客户端的自动化测试? AFAICT,身份验证希望让用户物理单击 "Allow" 按钮以授予我的应用程序访问其身份信息的权限,然后再生成授权代码。在自动化测试中,我想通过代码传递 username/password 等。你是怎么做到的?
从这里开始: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/
有很多东西需要吸收,但听起来您需要了解这些东西是如何协同工作的。希望这有帮助。
最近经历了这样的事情,我会尽量回答你的一些问题:
- 客户端应该从 Google 获取令牌,您可以将其原封不动地传递给 API:
function onSignIn(googleUser) {
var profile = googleUser.getBasicProfile();
var idToken = googleUser.getAuthResponse().id_token;
}
- 一个普通的 vanilla Controller 应该可以做到。客户端随后可以 post 那里的对象,至少包含该令牌加上客户端 ID(可能有助于了解请求的来源)甚至 providerUserId;
- 很遗憾,我对 Owin 堆栈不是很熟悉
- 完全端到端的集成测试可能会很棘手,尽管您可以通过 Selenium, or some mocking tool. The API however should be testable just by posting some fake data to that vanilla controller, although you might have to rely on some sort of mock implementation when you get to validating 之类的工具实现某些功能,该令牌通过 Google (尽管您也可以在服务器上手动验证它,如果您获得 Google public api 键)。
更新:
我没有完全访问您的设置的权限,但我希望以下代码可以帮助您使用 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。您可以从中获取声明并使用它们进行登录。请让我知道这是否有效,如果没有,请提供有关您的设置的更多详细信息(什么样的框架、客户端设置以及可能在启动文件中有关您的设置的更多详细信息)。
谢谢。
请查看此 link for details on how we can use Google as ID Provider. I am sure you might have looked at this link,以防您错过。如果这些链接中的 none 对您有用,请包括具体细节,说明您偏离链接中提到的内容的地方。
我假设您的要求与那些链接中指定的要求不同。因此,我将尝试单独回答您的问题。如果您还有其他问题,请告诉我。
- 当客户端用 Google API 完成身份验证后,它会返回一个 "code"。该代码仍然需要转换为令牌。那应该由谁负责——客户还是API? (如果只是为了更好地分配工作量,我倾向于将其作为客户的责任。)
Exchanging the code for access token is definitely the responsibility of the API as the token exchange involves sending the ClientId and Client Secret along with the code. Client secret is supposed to be saved on the server side (API) but not on the client
不管客户端传过来的是code还是token,我都需要能够在API中收到。我应该只使用一个普通的普通控制器来接收它,端点返回一个 AuthenticationProperties 类型的对象,还是有一些特殊的 OWIN 方法来做这个?
This should work seamlessly if you are using the Google provider as mentioned in the above links. If not, the endpoint should be an anonymous endpoint accepting the code and making a request to Google (may be by using HttpClient) to get the access token along with the profile object for user related information.
如果我使用的是普通控制器,我该如何验证我的令牌?换句话说,我如何访问 OWIN 上下文以便我可以将 AuthenticationTicket 标记为已验证?
You have to implement OnGrantAuthorizationCode as part of your MyAuthorizationProvider class. This gives access to the context to set validated to true.
如何编写模拟流程客户端的自动化测试? AFAICT,身份验证希望让用户物理单击 "Allow" 按钮以授予我的应用程序访问其身份信息的权限,然后再生成授权代码。在自动化测试中,我想通过代码传递 username/password 等。你是怎么做到的?
This can be achieved partially, but, with that partial test you can be sure of good test coverage against your code. So, you have to mock the call to the Google API and assume that you have retrieved a valid response (hard code the response you received from a valid manual test). Now test your code on how it behaves with the valid response. Mock the Google API cal for an invalid response and do the same. This is how we are testing our API now. This assumes that Google API is working fine and tests my code for both valid/ in-valid responses.
谢谢,
索玛.
所以我找到了自己的解决方案。它只是有点笨拙,不需要引用任何 Google OWIN 库,最重要的是,重用了我的 username/password 身份验证中的代码。
首先,我让应用调用与 username/password 相同的 Authenticate 端点,仅使用虚拟凭据,并添加包含令牌的 "GoogleToken" header .
在我的身份验证代码中,我检查 Google 令牌 header,如果它存在,请按照该代码路径在 Google 服务器上进行验证,获取电子邮件地址, link 我自己的用户 table。然后构建声明和返回新 API 令牌的其余过程遵循原始路径。
我负责我们产品的 API 方面。我们有几种不同的客户端,从浏览器到 iPad 再到 Chromebook。现在,我们所有的身份验证都是直接从客户端到我们的 API,使用用户名和密码。
我继承了一些使用 OAuth 进行身份验证的代码,使用通常的 username/password 设置。所以在我的 OwinAuthConfig
class 里面,我有:
var oAuthAuthorizationOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Authenticate"),
Provider = new MyAuthorizationProvider(),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
AllowInsecureHttp = true
};
app.UseOAuthAuthorizationServer(oAuthAuthorizationOptions);
然后,通过一些黑魔法,它连接到我的 MyAuthorizationProvider
class(它继承了 OAuthAuthorizationServerProvider
),并在登录时调用方法:
public override Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{ ... }
其中 context
包含重要的内容(Username
和 Password
),然后我可以使用它们来验证用户、建立他的声明、创建 AuthenticationTicket
和然后,此信息会神奇地 return 通过访问令牌等
一切都很好。
现在我有一个新要求 - 允许来自 Google 的第 3 方身份验证。在这种情况下,客户端应用程序 (iOS/Android/whatever) 使用 Google 进行身份验证,他们应该在 API 端将令牌(和任何其他所需信息)传递给我。在我这边,然后我需要重新验证 Google 令牌,并从 Google 获取所有用户信息(电子邮件、姓名等),然后我应该再次从中获取 link给我们的用户table,建立声明等,并return给客户端一个新的令牌,它将在所有后续调用中使用。
作为整个 OWIN 管道的新手,我不确定具体如何去做。我可以写一个新的 GoogleAuthController,它就像任何其他控制器一样,并且有一个 API 接受 Google 令牌,returns 新令牌和其他信息格式与 username/password 身份验证 API 相同。但是有两件事在困扰着我:
- 我有一种尴尬的感觉,就像这是新手做事的方式,重新发明轮子,而且真的有一种超酷的神奇方式可以将东西连接在一起,我宁愿使用它;和
- 在
MyAuthorizationProvider.GrantResourceOwnerCredentials()
中,我可以访问OAuthGrantResourceOwnerCredentialsContext
对象,这使我可以验证我的新AuthenticationTicket
。如果我在普通控制器中执行此操作,我不知道如何将该票证标记为已验证。
有什么线索吗?
编辑 我已经看到 Google 身份验证流程,如 here 所述。我仍然对如何最好地从 API 端管理流程感到困惑。客户端将获取授权代码,然后使用该授权代码调用 API。我明白了,然后我必须获取该授权代码并通过调用 Google API 将其转换为令牌。 (或者这应该是客户的责任?)无论哪种方式,我都需要使用该令牌返回到 Google API 并获取用户的姓名、电子邮件和头像图像,然后我需要将该电子邮件与我自己的数据库进行匹配,以识别用户并建立他们的声明。然后我需要 return 一个新的令牌,客户端可以使用它来连接到我。
让我更具体地说明我的问题,在我的问题结束之前 "too broad":
- 当客户端完成 Google API 的身份验证后,它会返回一个 "code"。该代码仍然需要转换为令牌。那应该由谁负责——客户还是API? (如果只是为了更好地分配工作量,我倾向于将其作为客户的责任。)
- 不管客户端传过来的是code还是token,我都需要能够在API中接收到。我应该只使用一个普通的香草控制器来接收它,端点 returning 一个类型
AuthenticationProperties
的对象,还是有一些特殊的 OWIN 方法来接收它? - 如果我使用的是普通控制器,我该如何验证我的令牌?换句话说,如何访问 OWIN 上下文以便我可以将
AuthenticationTicket
标记为已验证? - 如何编写模拟流程客户端的自动化测试? AFAICT,身份验证希望让用户物理单击 "Allow" 按钮以授予我的应用程序访问其身份信息的权限,然后再生成授权代码。在自动化测试中,我想通过代码传递 username/password 等。你是怎么做到的?
从这里开始: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/
有很多东西需要吸收,但听起来您需要了解这些东西是如何协同工作的。希望这有帮助。
最近经历了这样的事情,我会尽量回答你的一些问题:
- 客户端应该从 Google 获取令牌,您可以将其原封不动地传递给 API:
function onSignIn(googleUser) {
var profile = googleUser.getBasicProfile();
var idToken = googleUser.getAuthResponse().id_token;
}
- 一个普通的 vanilla Controller 应该可以做到。客户端随后可以 post 那里的对象,至少包含该令牌加上客户端 ID(可能有助于了解请求的来源)甚至 providerUserId;
- 很遗憾,我对 Owin 堆栈不是很熟悉
- 完全端到端的集成测试可能会很棘手,尽管您可以通过 Selenium, or some mocking tool. The API however should be testable just by posting some fake data to that vanilla controller, although you might have to rely on some sort of mock implementation when you get to validating 之类的工具实现某些功能,该令牌通过 Google (尽管您也可以在服务器上手动验证它,如果您获得 Google public api 键)。
更新:
我没有完全访问您的设置的权限,但我希望以下代码可以帮助您使用 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。您可以从中获取声明并使用它们进行登录。请让我知道这是否有效,如果没有,请提供有关您的设置的更多详细信息(什么样的框架、客户端设置以及可能在启动文件中有关您的设置的更多详细信息)。
谢谢。
请查看此 link for details on how we can use Google as ID Provider. I am sure you might have looked at this link,以防您错过。如果这些链接中的 none 对您有用,请包括具体细节,说明您偏离链接中提到的内容的地方。
我假设您的要求与那些链接中指定的要求不同。因此,我将尝试单独回答您的问题。如果您还有其他问题,请告诉我。
- 当客户端用 Google API 完成身份验证后,它会返回一个 "code"。该代码仍然需要转换为令牌。那应该由谁负责——客户还是API? (如果只是为了更好地分配工作量,我倾向于将其作为客户的责任。)
Exchanging the code for access token is definitely the responsibility of the API as the token exchange involves sending the ClientId and Client Secret along with the code. Client secret is supposed to be saved on the server side (API) but not on the client
不管客户端传过来的是code还是token,我都需要能够在API中收到。我应该只使用一个普通的普通控制器来接收它,端点返回一个 AuthenticationProperties 类型的对象,还是有一些特殊的 OWIN 方法来做这个?
This should work seamlessly if you are using the Google provider as mentioned in the above links. If not, the endpoint should be an anonymous endpoint accepting the code and making a request to Google (may be by using HttpClient) to get the access token along with the profile object for user related information.
如果我使用的是普通控制器,我该如何验证我的令牌?换句话说,我如何访问 OWIN 上下文以便我可以将 AuthenticationTicket 标记为已验证?
You have to implement OnGrantAuthorizationCode as part of your MyAuthorizationProvider class. This gives access to the context to set validated to true.
如何编写模拟流程客户端的自动化测试? AFAICT,身份验证希望让用户物理单击 "Allow" 按钮以授予我的应用程序访问其身份信息的权限,然后再生成授权代码。在自动化测试中,我想通过代码传递 username/password 等。你是怎么做到的?
This can be achieved partially, but, with that partial test you can be sure of good test coverage against your code. So, you have to mock the call to the Google API and assume that you have retrieved a valid response (hard code the response you received from a valid manual test). Now test your code on how it behaves with the valid response. Mock the Google API cal for an invalid response and do the same. This is how we are testing our API now. This assumes that Google API is working fine and tests my code for both valid/ in-valid responses.
谢谢, 索玛.
所以我找到了自己的解决方案。它只是有点笨拙,不需要引用任何 Google OWIN 库,最重要的是,重用了我的 username/password 身份验证中的代码。
首先,我让应用调用与 username/password 相同的 Authenticate 端点,仅使用虚拟凭据,并添加包含令牌的 "GoogleToken" header .
在我的身份验证代码中,我检查 Google 令牌 header,如果它存在,请按照该代码路径在 Google 服务器上进行验证,获取电子邮件地址, link 我自己的用户 table。然后构建声明和返回新 API 令牌的其余过程遵循原始路径。