使用 OWIN Identity 从多个 API 客户端注册 Web API 2 外部登录 [英] Registering Web API 2 external logins from multiple API clients with OWIN Identity

查看:20
本文介绍了使用 OWIN Identity 从多个 API 客户端注册 Web API 2 外部登录的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

在一台服务器上运行的 Web API 2 应用

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

<小时>

Josh,您肯定走在正确的轨道上,您的委托/联合身份验证 实现看起来相当不错(我想您已经使用了 Microsoft.Owin 的预定义 OWIN 中间件.安全性.Facebook/Google/Twitter).

您需要做的是创建您自己的自定义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 = 真,Provider = 新的 OAuthAuthorizationServerProvider{OnValidateClientRedirectUri = ValidateClientRedirectUri,OnValidateClientAuthentication = ValidateClientAuthentication,OnGrantResourceOwnerCredentials = GrantResourceOwnerCredentials,},AuthorizationCodeProvider = 新的 AuthenticationTokenProvider{OnCreate = CreateAuthenticationCode,OnReceive = ReceiveAuthenticationCode,},RefreshTokenProvider = 新的 AuthenticationTokenProvider{OnCreate = CreateRefreshToken,OnReceive = ReceiveRefreshToken,}});

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

您需要做的另一件事是在您的网络应用程序中添加 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.

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

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

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

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

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

  • Register new accounts with username and password
  • Register new accounts with Facebook/Google/Twitter/Microsoft
  • Log in
  • Retrieve pictures

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

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

I have studied most documents available on the authentication flow, like this:

I have read pretty much everything I can on the new Identity model in 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.

Here is the flow so far:

  • User browses to www.webpics.com/Login
  • www.webpics.com calls api.prettypictures.com/Account/ExternalLogins (with a returnUrl set 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/ExternalLogin with the name of the provider etc.
  • The API's ExternalLogin action 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.com now 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/ExternalLogin with a cookie that Google has set.

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.com and 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.com login.

I don't know how to facilitate this.

In fact at this point the browser ends up sat at the api.prettypictures.com/Account/ExternalLogin endpoint 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?

In the SPA app, it is done via AJAX and google.com will 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.

Help!

解决方案

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:

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:

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

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 authentication implementation seems pretty good (I imagine that you've used the predefined OWIN middleware from 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 OAuthAuthorizationServerMiddleware in your OWIN Startup class. You'll find it in the Microsoft.Owin.Security.OAuth Nuget package.

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").

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

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 AuthorizationController controller and Authorize methods (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 AuthorizeEndpointPath to use oauth2/ as a path base).

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:

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

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, GoogleOAuth2AuthenticatedContext and 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 GoogleOAuth2AuthenticationHandler to match the ones you've defined in your OAuth2 authorization server.

Then, add the Use method from your renamed/custom GoogleAuthenticationExtensions to your OWIN Startup class. I suggest using AuthenticationMode.Active so 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.

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

这篇关于使用 OWIN Identity 从多个 API 客户端注册 Web API 2 外部登录的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆