ASP.NET MVC + API和WCF,具有针对自定义数据库和活动目录的基于声明的授权和身份验证

时间:2015-11-18 13:14:59

标签: asp.net wcf authentication claims-based-identity identityserver3

我们正在开发两个(新)ASP.NET应用程序,它们使用MVC / Razor视图作为模板引擎来处理I18N / L10N(当前文化存储在每个请求的cookie中,并从中检索;文本从资源加载。)

两个应用程序通过与MVC应用程序在同一ASP.NET应用程序中托管的单独WebApis来使用相同的WCF服务。 API并由基于Web的应用程序(HTML / JS)访问。

应用程序 A 目前使用表单身份验证(用户凭据由WCF服务根据我们的应用程序数据库进行验证),应用程序 B 使用Windows身份验证。

TL; DR摘要:我们需要了解WCF服务中关于网络用户的内容。

我们需要:

  • 可以访问WCF服务中的当前(Web)用户标识
  • 传输有关该身份的可验证信息(例如角色,群组成员资格......),并使用该信息限制查询和操作(即仅允许查看和编辑您自己组中的数据)。
  • 透明地验证应用 B 中的用户(我们不希望IE中有单独的登录屏幕或弹出窗口)
  • 支持通过一次性登录进行登录,其中身份验证发生在带外(例如,用户获得的访问代码只是简单有效,这会对他/她自己进行身份验证,就像他使用他的凭据登录一样)
  • 具有短暂的会话/令牌生存期,但使用滑动过期 - 用户活动应延长其会话/令牌生存期。非活动用户应在短暂不活动后注销。
  • 与WCF服务通信时是否具有消息安全性(理想情况下,由于需要模拟/委派而没有基于证书的实际身份验证,因此具有证书安全性?)

到目前为止,我对此的想法和印象一直是:

  • 基于声明的授权可以很好地将授权与业务逻辑分离
  • 基于声明的身份验证/授权似乎可以传输我们限制可用数据和操作所需的所有信息(即从声明中读取组成员资格)
  • 基于令牌的身份验证是基于声明的身份验证(令牌是传输声明的方式)
  • 我需要一个安全令牌服务来验证用户(IdentityServer)
  • 可以在WCF频道创建期间以某种方式使用标记来传输当前(声明)主体或相应的标记。
  • 从表单迁移到基于令牌的身份验证时,我必须为我们的Web客户端使用资源所有者密码凭据流

到目前为止,我有:

  • 使用ROPC流程设置具有单个客户端的IdentityServer
  • 将OWIN添加到网络应用程序A并使用app.UseCookieAuthenticationapp.UseIdentityServerBearerTokenAuthentication设置身份验证,但我不太确定究竟是什么原因所以我对此不太满意现在。
  • 登录时(通过MVC)我通过TokenClient.RequestResourceOwnerPasswordAsync(username, password, scopes)从IdentityServer请求(访问?)令牌,尝试通过访问userinfo来构建ClaimsIdentity?端点并通过Request.GetOwinContext().Authentication.SignIn(id);设置Cookie。
  • 对基于令牌的身份验证和基于声明的授权如何工作的基本了解

我没有:

  • 相信我完全理解基于声明的授权是如何工作的,并且可以在WCF,MVC和WebApi中实现
  • 知道不同的OWIN中间件和扩展(UseIdentityServerBearerTokenAuthenticationUseOpenIdConnectAuthentication等)实际上做了什么,应该如何以及何时使用它们以及具有哪些安全隐患。
  • 知道wS2007FederationHttpBinding做了什么以及它用于什么,或者我必须在Startup.cs中配置什么以及需要在web.config或其他地方配置什么
  • 如何使用适当的证书SSL / HTTPS保护所有内容,以便我可以在团队开发期间以及部署中使用它(我们在每个开发人员以及每个构建配置中都有配置转换) )

基本上,我已经阅读了很多关于WCF,WIF等的内容,我不清楚当前的信息是什么,最佳实践是什么以及如何实现符合我们所有要求的内容。 IdentityServer的例子并没有给我带来太多帮助,因为对我来说,他们无法解释任何事情。

即使您只是帮助我更好地理解术语和技术,我们将非常感谢您的帮助。

P.S。:我们正在运行.NET 4.6

更新 我设法从IdentityServer检索令牌并查询userinfo端点以获取声明。结果我使用ClaimTypes.Email等而不是Constants.ClaimTypes.Email - 只有身份范围会在userinfo端点上产生声明,我在资源范围内指定了它们。

我的下一步是试图找出UseIdentityServerBearerTokenAuthentication如何阻止我访问任何内容以及如果我删除任何必需的范围,为什么它不会...

更新(2015-12-01) 我目前正尝试以某种方式透明地将令牌传输到WCF服务,并根据令牌使当前主体(或声明主体)可用。我还没有明确的方法来实现这一目标。

MVC和WebApi现在似乎工作正常:

使用OWIN cookie中间件保护MVC应用程序 - 在使用表单身份验证的登录时,我使用TokenClient和资源所有者密码凭据流。然后,我查询userinfo(通过UserInfoClient)和introspection(通过IntrospectionClient)端点来构建声明,创建ClaimsIdentity并将其保存在Cookie中。我还将访问令牌保存为声明。

var id = new ClaimsIdentity(listOfClaims, "Cookies");
this.Request.GetOwinContext().Authentication.SignIn(id);

陷阱:内省端点需要作为范围进行身份验证,而不是客户端 - 在样本中略有误导,客户端和范围具有相同的名称

要在每个请求上验证令牌,我将Provider的{​​{1}}配置为CookieAuthenticationOptions,我在new CookieAuthenticationProvider()期间查询IdentityServer的内省端点:< / p>

OnValidateIdentity

通过扩展用于设置WebApi的app.UseCookieAuthentication(new CookieAuthenticationOptions { AuthenticationType = "Cookies", LoginPath = new PathString("/User/Login"), LogoutPath = new PathString("/User/Logoff"), // setup more options etc.. Provider = new CookieAuthenticationProvider() { OnValidateIdentity = async context => { // validate etc. - and if it fails call: context.RejectIdentity(); } } } ,WebApi与cookie身份验证分离:

Register(HttpConfiguration config)

此外,我已经在owin启动中设置了// prevent use of owin cookie auth config.SuppressDefaultHostAuthentication(); // need bearer token auth config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType)); (基本上,这是我对WebApi做的唯一一件事,因为我有几条途径到几个Apis并且无法设置多个地图通过Ninject依赖注入......)。

IdentityServerBearerTokenAuthentication

当然,仅此一点只意味着角度应用程序无法获取任何数据 - 因此在单页面应用程序视图中,我将令牌作为常量注入配置,并通过配置{设置默认标头{1}}:

查看:

 app.Map(
    "/api",
    inner =>
    {
            inner.UseIdentityServerBearerTokenAuthentication(identityServerBearerTokenAuthenticationOptions);
    });

应用程式:

$httpProvider

...所以我现在唯一的问题就是如何将令牌转移到WCF服务以及如何在服务上设置该令牌的声明身份(无需明确地做到这一点 - 即我不会&#39 ; t我的合约需要一个单独的参数)

P.S。:我只能在<script type="text/javascript"> angular.module("myApp").constant("authorizationHeader", "Bearer @Model"); </script> 中配置WCF服务,因为我们正在使用自托管WCF服务和Ninject ......

更新 2015-12-10 成功的情况下!

我将参考令牌传送到WCF服务,类似于Dominick Baier建议的做法:http://leastprivilege.com/2015/07/02/give-your-wcf-security-architecture-a-makeover-with-identityserver3/

基本上归结为:

  • 将参考令牌包含在新myApp.config(["$httpProvider", "authorizationHeader", function ($httpProvider, authorizationHeader) { $httpProvider.defaults.headers.common["Authorization"] = authorizationHeader; }]);
  • app.config
  • 为该身份创建新的Claim
  • 使用ClaimsIdentity
  • 换行
  • 包装在SecurityTokenDescriptor
  • 通过Saml2SecurityTokenHandler创建频道(提示:缓存GenericXmlSecurityToken但不缓存this.ChannelFactory.CreateChannelWithIssuedToken(xmlToken);

这意味着我必须将绑定更改为ChannelFactory,将所有网址更改为使用Channel以及ws2007FederationHttpBindinghttps范围内的端口,以便在localhost上进行开发(因为Windows为这些端口预先配置了证书和访问控制列表 - 对于部署,您必须添加证书并允许WCF主机用户在那里托管HTTP / SSL服务。 如果可以看到任何元数据端点,那么它们也必须使用HTTPS(4430044399

要使用该绑定,安全性必须为binding="mexHttpsBinding"

在WCF端,我删除了所有<serviceMetadata httpGetEnabled="false" />并添加了我自己的TransportWithMessageCredentials,它解包引用令牌并使用IdentityServer的SecurityTokenHandler端点来构建身份(非常类似于IdentityServer中的示例) )。

可以在代码或app.config中完成(introspection是我保留所有这些内容的程序集):

ServiceCommunication

对于授权,我定义了自己的<configSections> <section name="system.identityModel" type="System.IdentityModel.Configuration.SystemIdentityModelSection, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" /> </configSections> <system.identityModel> <identityConfiguration name="identity"> <securityTokenHandlers> <clear /> <add type="ServiceCommunication.Authentication.IdentityServerWrappedReferenceTokenHandler, ServiceCommunication" /> </securityTokenHandlers> <claimsAuthorizationManager type="ServiceCommunication.Authorization.ClaimsAuthorizationManager, ServiceCommunication"/> </identityConfiguration> ,它处理被覆盖的ClaimsAuthorizationManager方法中的所有内容。注意:也为每个WCF合同方法调用该方法。

授权可以通过CheckAccess通过任何普通代码进行,也可以通过ClaimsPrincipalPermissionAttribute进行明确授权。甚至不必是WCF。在.NET 4.5中开箱即用

我在我的WCF服务中尽可能深入使用ClaimsPrincipalPermission,并在MVC / API控制器操作上使用。{/ p>

现在,我已获得所有用户的身份验证,阻止访问未经身份验证的用户(使用重定向登录)并保证只有授权用户才能访问特定方法。 :)

2 个答案:

答案 0 :(得分:1)

所以我终于解决了这一切:

  • 我使用IdentityServer3进行所有声明的身份验证和管理
  • app.UseCookieAuthentication使用我自己的CookieAuthenticationProvider验证MVC中的引用令牌,并像以前的表单身份验证一样处理登录
  • API的
  • app.UseIdentityServerBearerTokenAuthentication(每个http请求必须设置带有值Authorize的标头Bearer your-token-here,大多数JS框架允许您全局设置它。身份验证针对IdentityServer,我已经配置了ClientId和ClientSecret(实际上是ScopeId和ScopeSecret),因此它使用了introspection-endpoint。 小心:您只能获得该特定范围的声明,而不是其他范围。
  • 各种IdentityModel个客户端进行身份验证和验证(以及从userinfo和内省端点获取声明)
  • 通过Ws2007FederationHttpBindingTransportWithMessageCredentials安全
  • 包装的引用或jwt令牌
  • 我自己的SecurityTokenHandler在WCF服务上打开该令牌并验证它(并设置身份/主体)
  • 我自己的ClaimsAuthorizationManager通过ClaimsPrincipalPermissionAttribute
  • 进行授权

答案 1 :(得分:0)

新的互联网安全协议(如OAuth2和OpenID Connect)与WCF SOAP服务不兼容。

授权服务器在使用OAuth2和OpenID Connect协议时会发出JWT令牌。但是,当您使用WS2007FederationHttpBinding时,您的SOAP WCF服务需要在信封标头中使用SAML令牌。 IndentityServer does not issue SAML tokens

虽然可以使用JWT令牌的声明来发布和签署您自己的SAML令牌,但使用基于REST的服务替换WCF SOAP服务可能更容易,这些服务需要Authorization标头中的JWT令牌

我不确定您为什么要使用资源所有者密码凭据流。您可能需要查看using IdentityServer with an existing database并使用身份验证代码流。

P.S。 IdentityServerKatana(Microsoft的OWIN实现)都是开源的,因此您可以弄清楚所有这些代码实际上在做什么。