我想要以下架构(我已经为这个示例编造了产品名称):
在一台服务器上运行的 Web API 2 应用程序 http://api.prettypictures.com
在另一台服务器上运行的 MVC 5 客户端应用 http://www.webpics.com
我希望 www.webpics.com 客户端应用程序使用 Pretty Pictures API 来:
使用用户名和密码注册新帐户
在 Facebook/Google/Twitter/Microsoft 注册新帐户
登录
检索图片
除了在 Facebook、Google 等注册外部帐户外,上述所有工作都有效。
我无法制定正确的流程来从 API 的单独客户端用户创建外部帐户。
https://i.stack.imgur.com/fF67o.png
我已经阅读了几乎所有关于 OWIN 中新身份模型的内容。
我已经检查了 Visual Studio 2013 中的 SPA 模板。它演示了如何完成我需要的大部分工作,但前提是客户端和 API 位于同一主机上;如果我希望多个客户端访问我的 API 并能够让用户通过 Google 等进行注册。它不起作用,据我所知 OWIN 身份验证流程中断。
这是到目前为止的流程:
用户浏览到 www.webpics.com/Login
www.webpics.com 调用 api.prettypictures.com/Account/ExternalLogins(将 returnUrl 设置为返回到 www.webpics.com 的回调)并向用户显示结果链接
用户点击“谷歌”
浏览器使用提供者的名称等重定向到 api.prettypictures.com/Account/ExternalLogin。
API 的 ExternalLogin 操作实例化了对 google.com 的挑战
浏览器被重定向到 google.com
用户输入他们的用户名和密码(如果他们尚未登录到 google.com)
google.com 现在提供安全许可:“api.prettypictures.com”想访问您的电子邮件地址、姓名、妻子、孩子等。可以吗?
用户单击“是”并返回 api.prettypictures.com/Account/ExternalLogin 并使用 Google 设置的 cookie。
这就是我卡住的地方。接下来应该发生的事情是以某种方式通知客户端应用程序,用户已成功通过 google.com 进行身份验证,并获得一次性访问代码,以便稍后交换访问令牌。如有必要,客户端应用程序应有机会提示用户输入用户名以与他们的 google.com 登录相关联。
我不知道如何促进这一点。
事实上,此时浏览器在 Google 回调后最终位于 api.prettypictures.com/Account/ExternalLogin 端点。 API 已为 Google 登录,但客户端不知道如何处理。我应该将该 cookie 传送回 www.webpics.com 吗?
在 SPA 应用程序中,它是通过 AJAX 完成的,google.com 将返回一个令牌作为 URL 片段,这一切都很好,因为它都位于一个域上。但这在很大程度上违背了拥有多个客户端可以充分使用的“API”的意义。
帮助!
更新:自从我在一月份写这篇文章以来,情况发生了变化:MSFT 发布了他们的官方 OpenID 连接客户端中间件,我与@manfredsteyer 一起努力使 Katana 中内置的 OAuth2 授权服务器适应 OpenID 连接。这种组合产生了一个更简单、更强大的解决方案,不需要任何自定义客户端代码,并且与标准 OAuth2/OpenID 连接客户端 100% 兼容。我在一月份提到的不同步骤现在可以只用几行代替:
服务器:
app.UseOpenIdConnectServer(options =>
{
options.TokenEndpointPath = new PathString("/connect/token");
options.SigningCredentials.AddCertificate(certificate);
options.Provider = new CustomOpenIdConnectServerProvider();
});
客户:
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
Authority = "http://localhost:55985/",
ClientId = "myClient",
ClientSecret = "secret_secret_secret",
RedirectUri = "http://localhost:56854/oidc"
});
您可以在 GitHub 存储库中找到所有详细信息(以及不同的示例):
https://github.com/aspnet-contrib/AspNet.Security.OpenIdConnect.Server
https://github.com/aspnet-contrib/AspNet.Security.OpenIdConnect.Server/tree/dev/samples/Nancy
Josh,您肯定走在正确的轨道上,并且您的委托/联合身份验证 实现看起来相当不错(我想您已经使用了来自 Microsoft.Owin.Security.Facebook/Google/Twitter
的预定义 OWIN 中间件)。
您需要做的是创建自己的自定义 OAuth2 授权服务器。您有很多选项可以实现这一目标,但最简单的一种可能是将 OAuthAuthorizationServerMiddleware
插入您的 OWIN Startup 类。您可以在 Microsoft.Owin.Security.OAuth
Nuget 包中找到它。
虽然最佳实践是创建一个单独的项目(通常称为“AuthorizationServer”),但我个人更喜欢将它添加到我的“API 项目”中,因为它不打算跨多个 API 使用(在这里,您必须插入它在托管“api.prettypictures.com”的项目中)。
您会在 Katana 存储库中找到一个很棒的示例:
https://katanaproject.codeplex.com/SourceControl/latest#tests/Katana.Sandbox.WebServer/Startup.cs
app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions
{
AuthorizeEndpointPath = new PathString("/oauth2/authorize"),
TokenEndpointPath = new PathString("/oauth2/token"),
ApplicationCanDisplayErrors = true,
AllowInsecureHttp = true,
Provider = new OAuthAuthorizationServerProvider
{
OnValidateClientRedirectUri = ValidateClientRedirectUri,
OnValidateClientAuthentication = ValidateClientAuthentication,
OnGrantResourceOwnerCredentials = GrantResourceOwnerCredentials,
},
AuthorizationCodeProvider = new AuthenticationTokenProvider
{
OnCreate = CreateAuthenticationCode,
OnReceive = ReceiveAuthenticationCode,
},
RefreshTokenProvider = new AuthenticationTokenProvider
{
OnCreate = CreateRefreshToken,
OnReceive = ReceiveRefreshToken,
}
});
不要犹豫,浏览整个项目,看看授权同意书是如何使用简单的 Razor 文件实现的。如果您更喜欢 ASP.NET MVC 或 NancyFX 等更高级别的框架,请创建自己的 AuthorizationController
控制器和 Authorize
方法(确保同时接受 GET 和 POST)并使用属性路由来匹配 OAuth2 中定义的 AuthorizeEndpointPath授权服务器(即我的示例中的 [Route("oauth2/authorize")]
,我已将 AuthorizeEndpointPath
更改为使用 oauth2/
作为路径库)。
您需要做的另一件事是在您的 Web 应用程序中添加 OAuth2 授权客户端。不幸的是,Katana 中没有通用的 OAuth2 客户端支持,您必须自己构建。我亲自向 Katana 团队提交了一份提案,但被拒绝了。但不要惊慌,这很容易做到:
从位于那里的 Microsoft.Owin.Security.Google 存储库复制相应的文件:https://katanaproject.codeplex.com/SourceControl/latest#src/Microsoft.Owin.Security.Google/GoogleOAuth2AuthenticationHandler.cs
您将需要 GoogleOAuth2AuthenticationHandler
、GoogleOAuth2AuthenticationMiddleware
、GoogleOAuth2AuthenticationOptions
、GoogleAuthenticationExtensions
(您必须删除与 Google OpenID 实现相对应的前 2 个方法)、IGoogleOAuth2AuthenticationProvider
、GoogleOAuth2ReturnEndpointContext
、GoogleOAuth2AuthenticationProvider
、 GoogleOAuth2AuthenticatedContext
和 GoogleOAuth2ApplyRedirectContext
。将这些文件插入托管“webpics.com”的项目后,请相应地重命名它们并更改 GoogleOAuth2AuthenticationHandler
中的授权和访问令牌端点 URL 以匹配您在 OAuth2 授权服务器中定义的那些。
然后,将重命名/自定义 GoogleAuthenticationExtensions
中的 Use 方法添加到 OWIN Startup 类。我建议使用 AuthenticationMode.Active
,以便您的用户将被直接重定向到您的 API OAuth2 授权端点。因此,您应该禁止“api.prettypictures.com/Account/ExternalLogins”往返并让 OAuth2 客户端中间件更改 401 响应以将客户端重定向到您的 API。
祝你好运。如果您需要更多信息,请不要犹豫;)
redirect_uri
(例如http://www.webpic.com/signin-prettypictures
)时,我应该在查询字符串中输入什么内容,以便中间件日志知道该怎么做?