ChatGPT解决这个技术问题 Extra ChatGPT

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

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

在一台服务器上运行的 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”的意义。

帮助!

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

K
Kévin Chalet

更新:自从我在一月份写这篇文章以来,情况发生了变化: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 个方法)、IGoogleOAuth2AuthenticationProviderGoogleOAuth2ReturnEndpointContextGoogleOAuth2AuthenticationProviderGoogleOAuth2AuthenticatedContextGoogleOAuth2ApplyRedirectContext。将这些文件插入托管“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:当然,请在此处查看我的答案:stackoverflow.com/questions/28487586/…
@CularBytes 我会看看你的其他“POST”