75

我想要以下架构(我已经为这个示例编造了产品名称):

在一台服务器上运行的 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 的单独客户端用户创建外部帐户。

我研究了身份验证流程中可用的大多数文档,如下所示: 在此处输入图像描述

我已经阅读了几乎所有关于 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”的意义。

帮助!

4

1 回答 1

46

更新:自从我在一月份写这篇文章以来,情况发生了变化: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,您绝对走在正确的轨道上,并且您的委托/联合身份验证实现看起来相当不错(我想您已经使用了来自 的预定义 OWIN 中间件Microsoft.Owin.Security.Facebook/Google/Twitter)。

您需要做的是创建自己的自定义OAuth2 授权服务器。您有很多选择来实现这一点,但最简单的一种可能是插入OAuthAuthorizationServerMiddleware您的 OWIN Startup 类。你会在Microsoft.Owin.Security.OAuthNuget 包中找到它。

虽然最佳实践是创建一个单独的项目(通常称为“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")]在我的示例,我已将其更改AuthorizeEndpointPathoauth2/用作路径基础)。

您需要做的另一件事是在您的 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 个方法)、IGoogleOAuth2AuthenticationProviderGoogleOAuth2ReturnEndpointContext、和。将这些文件插入托管“webpics.com”的项目后,相应地重命名它们并更改授权和访问令牌端点 URL以匹配您在 OAuth2 授权服务器中定义的那些。GoogleOAuth2AuthenticationProviderGoogleOAuth2AuthenticatedContextGoogleOAuth2ApplyRedirectContextGoogleOAuth2AuthenticationHandler

然后,将重命名/自定义中的 Use 方法添加GoogleAuthenticationExtensions到 OWIN Startup 类。我建议使用AuthenticationMode.Active这样您的用户将被直接重定向到您的 API OAuth2 授权端点。因此,您应该禁止“api.prettypictures.com/Account/ExternalLogins”往返并让 OAuth2 客户端中间件更改 401 响应以将客户端重定向到您的 API。

祝你好运。如果您需要更多信息,请不要犹豫;)

于 2014-01-22T20:01:04.587 回答