使用 OWIN 身份从多个 API 客户端注册 Web API 2 外部登录

Posted

技术标签:

【中文标题】使用 OWIN 身份从多个 API 客户端注册 Web API 2 外部登录【英文标题】:Registering Web API 2 external logins from multiple API clients with OWIN Identity 【发布时间】:2014-02-05 16:56:53 【问题描述】:

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

在一台服务器上运行的 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)并将生成的链接显示给用户 用户点击“Google” 浏览器重定向到 api.prettypictures.com/Account/ExternalLogin 并带有提供者的名称等。 API 的 ExternalLogin 操作实例化了对 google.com 的挑战 浏览器被重定向到 google.com 用户输入他们的用户名和密码(如果他们尚未登录 google.comgoogle.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”的意义。

救命!

【问题讨论】:

嗨乔希!我目前也在做这件事。我们有一个 Web Api 和一个 html5/angularJS SPA,我们想使用 google/facebook 进行身份验证。您没有博客或 github 存储库,其中包含有关如何解决此问题的演示?会很感兴趣! 嗨阿什坎,很遗憾我没有!您是否在与 Web API 不同的域上运行您的 SPA(如上所述)? 是的,我们正在开发一个 phonegap 应用程序,所以我们有一个 Web API 作为我们的后端和一个纯 html5/angularjs SPA 作为我们在不同域上的前端,这将成为稍后将成为的应用程序从用户手机访问 API。 Josh 或 @AshkanAldini ,你最终解决了这个问题吗?我正在尝试做类似的事情,Pinpoint 的回答很有帮助,但我仍然对实现感到困惑。 【参考方案1】:

更新:自从我在一月份写这篇文章后,情况发生了变化: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

您需要GoogleOAuth2AuthenticationHandlerGoogleOAuth2AuthenticationMiddlewareGoogleOAuth2AuthenticationOptionsGoogleAuthenticationExtensions(您必须删除与 Google OpenID 实现相对应的前 2 个方法)、IGoogleOAuth2AuthenticationProviderGoogleOAuth2ReturnEndpointContext、@ 987654343@、GoogleOAuth2AuthenticatedContextGoogleOAuth2ApplyRedirectContext。在托管“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,我在查询字符串中输入了什么以便中间件日志知道该怎么做? (我尝试将状态作为查询字符串参数放在那里,但中间件似乎只是吞下它并将我重定向到我的客户端主页) 很高兴听到!我不知道你是否已经解决了上一个问题,但我想在传递给 IAuthenticationManager.Challenge 的 AuthenticationProperties 上设置 RedirectUri 可以解决问题;) @mayabelle:当然,请在此处查看我的答案:***.com/questions/28487586/… @CularBytes 我会看看你的其他“POST”

以上是关于使用 OWIN 身份从多个 API 客户端注册 Web API 2 外部登录的主要内容,如果未能解决你的问题,请参考以下文章

.NET Web API 2 OWIN 持有者令牌身份验证

具有混合身份验证 JWT 和 SAML 的 ASP.NET Web API 2.2 OWIN

Web Api OWIN - 如何在每个请求上验证令牌

具有多个 OIDC 身份验证配置的 OWIN

使用 Asp.Net 下的 owin 和 LinkedIn 身份验证提供程序进行 WebApi 身份验证

Web API 中的 OWIN CORS 问题