首页 文章

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

提问于
浏览
71

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

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

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

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

  • 使用用户名和密码注册新帐户

  • 使用Facebook / Google / Twitter / Microsoft注册新帐户

  • 登录

  • 检索图片

除了在Facebook,Google等注册外部账户外,所有上述工作均有效 .

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

我已经研究了认证流程中可用的大多数文档,如下所示:
enter image description here

我已经在OWIN的新身份模型上阅读了我所能做的一切 .

我已经在Visual Studio 2013中检查了SPA模板 . 它演示了如何完成我需要的大部分工作,但仅限于客户端和API位于同一主机上时;如果我希望多个客户端访问我的API并且能够让用户通过谷歌等注册,那么它就不起作用,而且我可以告诉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.com

  • google.com 现在提供安全许可: "api.prettypictures.com" would like access to your email address, name, wife, children etc. Is this OK?

  • 用户点击"Yep"并使用Google设置的Cookie重新收回 api.prettypictures.com/Account/ExternalLogin .

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

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

实际上,此时浏览器在谷歌回调后最终坐在 api.prettypictures.com/Account/ExternalLogin endpoints . 该API已登录Google,但客户端不知道如何处理该问题 . 我应该把那个 Cookies 送回 www.webpics.com 吗?

在SPA应用程序中,它通过AJAX完成, google.com 将返回一个令牌作为URL片段,它都可以很好地工作,因为它都位于一个域上 . 但这远远超过了多个客户端可以充分利用"API"的重点 .

救命!

1 回答

  • 46

    Update: things have changed since I wrote this post in January :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"
    });
    

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

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

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


    Josh,你肯定是在正确的轨道上,你的_717324实现似乎相当不错(我想你已经使用了 Microsoft.Owin.Security.Facebook/Google/Twitter 预定义的OWIN中间件) .

    您需要做的是创建自己的自定义 OAuth2 authorization server . 你有很多选择来实现这一目标,但最简单的方法可能就是在你的OWIN Startup类中插入 OAuthAuthorizationServerMiddleware . 你会在 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 中的授权和访问令牌 endpoints URL,以匹配您在OAuth2授权服务器中定义的URL .

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

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

相关问题