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


75

我想要以下架构(在此示例中,我组成了产品名称):

在一台服务器上运行的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中新Identity模式的几乎所有内容。

我已经检查了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.com
  • google.com现在提供安全检查:“ api.prettypictures.com”希望访问您的电子邮件地址,姓名,妻子,子女等。可以吗?
  • 用户单击“是”,并使用Google设置的cookie带回到api.prettypictures.com/Account/ExternalLogin

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

我不知道该怎么做。

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

在SPA应用程序中,这是通过AJAX完成的,并且google.com将返回令牌作为URL片段,并且由于它们都位于一个域中,因此效果很好。但是,这与拥有多个客户端可以完全使用的“ API”的许多观点不符。

救命!


嘿乔希!我目前也在研究这个问题。我们有一个Web Api和一个我们想使用google / facebook进行身份验证的html5 / angularJS SPA。您没有有关如何解决此问题的演示的博客或github存储库。会很有兴趣的!
2014年

嗨,阿什坎,不幸的是我没有!您是否在与Web API不同的域上运行SPA(如上所述)?
2014年

是的,我们正在开发一个phonegap应用程序,因此我们有一个Web API作为我们的后端,而一个纯html5 / angularjs SPA作为我们在另一个域上的前端,稍后将成为可从用户电话访问API的应用程序。
Ashkan Hovold 2014年

Josh或@AshkanAldini,您最终解决了这个问题吗?我正在尝试做类似的事情,Pinpoint的回答很有帮助,但是对于实现仍然感到困惑。
mayabelle

Answers:


46

更新:自从我在一月份写这篇文章以来,情况发生了变化:MSFT发布了他们的官方OpenID Connect客户端中间件,并且我与@manfredsteyer一起努力使Katana中内置的OAuth2授权服务器适应OpenID connect。这种组合可带来更轻松,更强大的解决方案,不需要任何自定义客户端代码,并且与标准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,您肯定走在正确的轨道上,您的委派/联合身份验证实现似乎还不错(我想您已经使用了来自的预定义OWIN中间件Microsoft.Owin.Security.Facebook/Google/Twitter)。

您需要做的是创建自己的自定义OAuth2授权服务器。您可以通过多种选择来实现这一目标,但是最简单的选择可能是将其插入OAuthAuthorizationServerMiddlewareOWIN Startup类。您可以在Microsoft.Owin.Security.OAuthNuget包中找到它。

虽然最佳做法是创建一个单独的项目(通常称为“ 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(你就必须删除对应谷歌的OpenID执行第2种方法)IGoogleOAuth2AuthenticationProviderGoogleOAuth2ReturnEndpointContextGoogleOAuth2AuthenticationProviderGoogleOAuth2AuthenticatedContextGoogleOAuth2ApplyRedirectContext。将这些文件插入托管“ webpics.com”的项目后,请相应地重命名它们,并更改授权和访问令牌端点URL,GoogleOAuth2AuthenticationHandler以匹配您在OAuth2授权服务器中定义的URL 。

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

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


嗨,非常感谢您的回答,它几乎在所有正确的方向上指出了我,而我已经快到了。我已经使用您指向的类创建了自己的中间件实现。我遇到的问题是,当我重定向回客户端的原始文件时redirect_uri,例如http://www.webpic.com/signin-prettypictures,应在查询字符串中放入什么内容,以便中间件日志知道该怎么做?
2014年

(我尝试过将状态作为查询字符串参数放在那儿,但是中间件似乎只是吞下了它,然后将我重定向到我的客户端主页)
joshcomley2014年

很高兴听到!我不知道您是否已经解决了最后一个问题,但是我想在传递给IAuthenticationManager.Challenge的AuthenticationProperties上设置RedirectUri可以解决问题;)
KévinChalet 2014年

1
@mayabelle:肯定的,请在这里看到我的回答:stackoverflow.com/questions/28487586/...
凯文木屋

1
@CularBytes我看一下您的其他“ POST”
Worthy7 '18
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.