asp.net-mvc 使用 OWIN Identity 从多个 API 客户端注册 Web API 2 外部登录

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21167648/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 03:26:59  来源:igfitidea点击:

Registering Web API 2 external logins from multiple API clients with OWIN Identity

asp.net-mvcoauth-2.0asp.net-identityowinasp.net-web-api2

提问by joshcomley

I would like the following architecture (I've made up the product name for this example):

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

Web API 2 application running on one serverhttp://api.prettypictures.com

在一台服务器上运行的 Web API 2 应用程序http://api.prettypictures.com

MVC 5 client app running on another serverhttp://www.webpics.com

在另一台服务器上运行的 MVC 5 客户端应用程序http://www.webpics.com

I would like www.webpics.comclient app to use the Pretty Pictures API to:

我希望www.webpics.com客户端应用程序使用 Pretty Pictures API 来:

  • Register new accounts with username and password
  • Register new accounts with Facebook/Google/Twitter/Microsoft
  • Log in
  • Retrieve pictures
  • 使用用户名和密码注册新帐户
  • 在 Facebook/Google/Twitter/Microsoft 注册新帐户
  • 登录
  • 检索图片

All of the above works except registering external accounts with Facebook, Google etc.

除了在 Facebook、Google 等上注册外部帐户外,上述所有方法都有效。

I cannot work out the correct flow to create an externalaccount from a separate client user of the API.

我无法确定从 API 的单独客户端用户创建外部帐户的正确流程。

I have studied most documents available on the authentication flow, like this: enter image description here

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

I have read pretty much everything I can on the new Identity model in OWIN.

我已经阅读了关于 OWIN 中新身份模型的几乎所有内容。

I've examined the SPA template in Visual Studio 2013. It demonstrates how to do most of what I need but only when the client and the API are on the same host; if I want multiple clients accessing my API and being able to let users sign up via Google etc. it doesn't work and as far as I can tell the OWIN authentication flow breaks.

我已经检查了 Visual Studio 2013 中的 SPA 模板。它演示了如何完成我需要的大部分工作,但前提是客户端和 API 位于同一主机上;如果我希望多个客户端访问我的 API 并能够让用户通过 Google 等注册。它不起作用,据我所知,OWIN 身份验证流程中断了。

Here is the flow so far:

这是到目前为止的流程:

  • User browses to www.webpics.com/Login
  • www.webpics.comcalls api.prettypictures.com/Account/ExternalLogins(with a returnUrlset to go back to a callback at www.webpics.com) and displays the resulting links to the user
  • The user clicks "Google"
  • The browser redirects to api.prettypictures.com/Account/ExternalLoginwith the name of the provider etc.
  • The API's ExternalLoginaction instantiates a challenge to google.com
  • The browser is redirected to google.com
  • The user enters their username and password (if they are not already logged in to google.com)
  • google.comnow presents the security clearance: "api.prettypictures.com" would like access to your email address, name, wife, children etc. Is this OK?
  • User clicks "Yep" and is taken back to api.prettypictures.com/Account/ExternalLoginwith a cookie that Google has set.
  • 用户浏览到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。

This is where I've got stuck. What is supposed to happen next is somehow the client app should be notified that the user has successfully authenticated with google.comand be given a single use access code to swap for an access token later on. The client app should have the opportunity, if necessary, to prompt the user for a username to associate with their google.comlogin.

这是我被卡住的地方。接下来应该发生的事情是以某种方式通知客户端应用程序用户已成功通过google.com进行身份验证,并获得一次性访问代码以稍后交换访问令牌。如有必要,客户端应用程序应该有机会提示用户输入与他们的google.com登录名相关联的用户名。

I don't know how to facilitate this.

我不知道如何促进这一点。

In fact at this point the browser ends up sat at the api.prettypictures.com/Account/ExternalLoginendpoint after the callback from Google. The API is signed in for Google but the client doesn't know how to deal with that. Should I pipe that cookie back to www.webpics.com?

事实上,在Google 回调之后,此时浏览器最终位于api.prettypictures.com/Account/ExternalLogin端点。API 已为 Google 登录,但客户端不知道如何处理。我应该将该 cookie 传送回www.webpics.com吗?

In the SPA app, it is done via AJAX and google.comwill return an token as a URL fragment and it all works nicely because it all sits on one domain. But that defies much of the point of having an "API" that multiple clients can fully use.

在 SPA 应用程序中,它是通过 AJAX 完成的,google.com将返回一个令牌作为 URL 片段,这一切都运行良好,因为它们都位于一个域中。但这违背了拥有多个客户端可以完全使用的“API”的大部分意义。

Help!

帮助!

采纳答案by Kévin Chalet

Update: things have changed since I wrote this post in January: MSFT released their official OpenID connect client middleware and I worked hard with @manfredsteyer to adapt the OAuth2 authorization server built in Katana to OpenID connect. This combination results in a far easier and far more powerful solution that doesn't require any custom client code and is 100% compatible with standard OAuth2/OpenID connect clients. The different steps I mentioned in January can now be replaced by just a few lines:

更新:自从我在一月份写这篇文章以来,情况发生了变化:MSFT 发布了他们的官方 OpenID 连接客户端中间件,我与 @manfredsteyer 一起努力使 Katana 中内置的 OAuth2 授权服务器适应 OpenID 连接。这种组合产生了一个更简单、更强大的解决方案,不需要任何自定义客户端代码,并且与标准 OAuth2/OpenID 连接客户端 100% 兼容。我在 1 月份提到的不同步骤现在可以用几行代码代替:

Server:

服务器:

app.UseOpenIdConnectServer(options =>
{
    options.TokenEndpointPath = new PathString("/connect/token");
    options.SigningCredentials.AddCertificate(certificate);

    options.Provider = new CustomOpenIdConnectServerProvider();
});

Client:

客户:

app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
    Authority = "http://localhost:55985/",

    ClientId = "myClient",
    ClientSecret = "secret_secret_secret",
    RedirectUri = "http://localhost:56854/oidc"
});

You can find all the details (and different samples) on the GitHub repository:

您可以在 GitHub 存储库中找到所有详细信息(和不同示例):

https://github.com/aspnet-contrib/AspNet.Security.OpenIdConnect.Server

https://github.com/aspnet-contrib/AspNet.Security.OpenIdConnect.Server

https://github.com/aspnet-contrib/AspNet.Security.OpenIdConnect.Server/tree/dev/samples/Nancy

https://github.com/aspnet-contrib/AspNet.Security.OpenIdConnect.Server/tree/dev/samples/Nancy



Josh, you're definitely on the right track and your delegated/federated authenticationimplementation seems pretty good (I imagine that you've used the predefined OWIN middleware from Microsoft.Owin.Security.Facebook/Google/Twitter).

Josh,你绝对是在正确的轨道上,你的委托/联合身份验证实现看起来很不错(我想你已经使用了预定义的 OWIN 中间件Microsoft.Owin.Security.Facebook/Google/Twitter)。

What you need to do is creating your own custom OAuth2 authorization server. You have plenty of options to achieve that, but the easiest one is probably to plug the OAuthAuthorizationServerMiddlewarein your OWIN Startup class. You'll find it in the Microsoft.Owin.Security.OAuthNuget package.

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

While the best practice would be to create a separate project (often called "AuthorizationServer"), I personally prefer adding it to my "API project" when it is not meant to be used across multiple API (here, you would have to insert it in the project hosting "api.prettypictures.com").

虽然最佳实践是创建一个单独的项目(通常称为“AuthorizationServer”),但我个人更喜欢将它添加到我的“API 项目”中,因为它不打算跨多个 API 使用(在这里,您必须插入它在托管“api.prettypictures.com”的项目中)。

You'll find a great sample in the Katana repository:

您将在 Katana 存储库中找到一个很棒的示例:

https://katanaproject.codeplex.com/SourceControl/latest#tests/Katana.Sandbox.WebServer/Startup.cs

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,
    }
});

Don't hesitate to browse the whole project to see how the authorization consent form has been implemented using simple Razor files. If you prefer a higher-level framework like ASP.NET MVC or NancyFX, create your own AuthorizationControllercontroller and Authorizemethods (make sure to accept both GET and POST) and use Attribute Routing to match the AuthorizeEndpointPath defined in your OAuth2 authorization server (ie. [Route("oauth2/authorize")]in my sample, where I've changed the AuthorizeEndpointPathto use oauth2/as a path base).

不要犹豫,浏览整个项目,看看授权同意书是如何使用简单的 Razor 文件实现的。如果您更喜欢 ASP.NET MVC 或 NancyFX 等更高级别的框架,请创建您自己的AuthorizationController控制器和Authorize方法(确保同时接受 GET 和 POST)并使用属性路由来匹配您的 OAuth2 授权服务器中定义的 AuthorizeEndpointPath(即[Route("oauth2/authorize")]在我的示例,我已将其更改AuthorizeEndpointPathoauth2/用作路径基础)。

The other thing you need to do is adding an OAuth2 authorization client in your web app. Unfortunately, there's no generic OAuth2 client support in Katana, and you'll have to build your own. I've personally submitted a proposal to the Katana team, but it has been refused. But don't panic, it's rather easy to do:

您需要做的另一件事是在您的 Web 应用程序中添加 OAuth2 授权客户端。不幸的是,Katana 中没有通用的 OAuth2 客户端支持,您必须自己构建。我个人向​​ Katana 团队提交了一份提案,但被拒绝了。但不要惊慌,这很容易做到:

Copy the appropriate files from the Microsoft.Owin.Security.Google repository located there: https://katanaproject.codeplex.com/SourceControl/latest#src/Microsoft.Owin.Security.Google/GoogleOAuth2AuthenticationHandler.cs

从位于那里的 Microsoft.Owin.Security.Google 存储库中复制相应的文件:https: //katanaproject.codeplex.com/SourceControl/latest#src/Microsoft.Owin.Security.Google/GoogleOAuth2AuthenticationHandler.cs

You'll need GoogleOAuth2AuthenticationHandler, GoogleOAuth2AuthenticationMiddleware, GoogleOAuth2AuthenticationOptions, GoogleAuthenticationExtensions(you'll have to remove the first 2 methods corresponding to the Google OpenID implementation), IGoogleOAuth2AuthenticationProvider, GoogleOAuth2ReturnEndpointContext, GoogleOAuth2AuthenticationProvider, GoogleOAuth2AuthenticatedContextand GoogleOAuth2ApplyRedirectContext. Once you've inserted these files in your project hosting "webpics.com", rename them accordingly and change the authorization and access token endpoints URL in GoogleOAuth2AuthenticationHandlerto match the ones you've defined in your OAuth2 authorization server.

您将需要GoogleOAuth2AuthenticationHandler, GoogleOAuth2AuthenticationMiddleware, GoogleOAuth2AuthenticationOptions, GoogleAuthenticationExtensions(您必须删除与 Google OpenID 实现相对应的前 2 个方法)IGoogleOAuth2AuthenticationProviderGoogleOAuth2ReturnEndpointContextGoogleOAuth2AuthenticationProviderGoogleOAuth2AuthenticatedContextGoogleOAuth2ApplyRedirectContext。将这些文件插入到托管“webpics.com”的项目中后,相应地重命名它们并更改授权和访问令牌端点 URLGoogleOAuth2AuthenticationHandler以匹配您在 OAuth2 授权服务器中定义的那些。

Then, add the Use method from your renamed/custom GoogleAuthenticationExtensionsto your OWIN Startup class. I suggest using AuthenticationMode.Activeso that your users will be directly redirected to your API OAuth2 authorization endpoint. Thus, you should suppress the "api.prettypictures.com/Account/ExternalLogins" roundtrip and let the OAuth2 client middleware alter 401 responses to redirect the clients to your API.

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

Good luck. And don't hesitate if you need more information ;)

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