通过Session Security Token进行身份验证的网站,需要将其传递给WCF服务

时间:2014-06-19 14:12:49

标签: .net wcf wif claims-based-identity

我有一个简单的.NET 4.5 MVC网站。登录后,会创建一个带有一些测试声明的ClaimsPrincipal

List<Claim> claims = new List<Claim>();
claims.Add(new Claim("Test", "Test"));
claims.Add(new Claim(ClaimTypes.NameIdentifier, "nameid"));
var id = new ClaimsIdentity(claims, "Forms");
var cp = new ClaimsPrincipal(id);

var token = new SessionSecurityToken(cp);
FederatedAuthentication.SessionAuthenticationModule.WriteSessionTokenToCookie(token);

web.config能够实现这一目标:

<!-- (have snipped out standard, not interesting web.config) -->
<configSections>
     <section name="system.identityModel" type="System.IdentityModel.Configuration.SystemIdentityModelSection, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
     <section name="system.identityModel.services" type="System.IdentityModel.Services.Configuration.SystemIdentityModelServicesSection, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />

<system.webServer>
     <modules runAllManagedModulesForAllRequests="true">
     <remove name="FormsAuthenticationModule" />
     <add name="SessionAuthenticationModule" type="System.IdentityModel.Services.SessionAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="managedHandler" />

<system.identityModel.services>
     <federationConfiguration>
     <cookieHandler requireSsl="false" persistentSessionLifetime="2"/>

从网络应用程序的其他地方,我可以使用ClaimsPrincipal.Current来获取声明。

发送到WCF服务

我需要将这些声明发送到友好的WCF服务(仅限Intranet)。从上面可以看出,令牌是在Web应用程序中创建的,而不是在STS上创建的。我希望能够将该令牌传递给WCF服务,并让服务将其设置为ClaimsPrincipal。

该服务如下:

// IClaimsCheckService
[ServiceContract]
public interface IClaimsCheckService
{
    [OperationContract]
    void CheckClaims();

// ClaimsCheckService.svc
public class ClaimsCheckService : IClaimsCheckService
{
    public void CheckClaims()
    {
        var claimsPrincipal = ClaimsPrincipal.Current;
    }
}

服务器web.config是:                       

<system.serviceModel>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
    <behaviors>
       <serviceBehaviors>
          <behavior>
             <serviceAuthorization principalPermissionMode="Always"  />
             <serviceCredentials useIdentityConfiguration="true" />
             <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
             <serviceDebug includeExceptionDetailInFaults="false"/>

客户端的web.config - 这是上面描述的MVC网站,此配置是上面代码段的其余配置。

<system.serviceModel>
    <behaviors>
        <endpointBehaviors>
            <behavior>
                 <clientCredentials useIdentityConfiguration="true">
                      <serviceCertificate>
                          <authentication certificateValidationMode="None"/>
                      </serviceCertificate>
                 </clientCredentials>
            </behavior>
        </endpointBehaviors>
    </behaviors>
    <bindings>
        <basicHttpBinding>
            <binding name="BasicHttpBinding_IClaimsCheckService" />
        </basicHttpBinding>
    </bindings>
    <client>
        <endpoint address="http://localhost:59343/ClaimsCheckService.svc"
            binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IClaimsCheckService"
            contract="CCS.IClaimsCheckService" name="BasicHttpBinding_IClaimsCheckService" />
    </client>
</system.serviceModel>

我读过Dominick Baier关于WCF and Identity in .NET 4.5的精彩系列。我也读过密集的MSDN article on Claims based authorization.与其他问题不同,我没有使用STS,而是在网站上创建联合令牌。

我期待什么

当调用服务时,我希望WCF客户端将客户端线程中的Principal发送到WCF服务,这样当我在服务器上执行var claimsPrincipal = ClaimsPrincipal.Current;时,我会获得相同的Principal。

会发生什么

ClaimsPrincipal.Current为空(新),不包含客户端的任何信息。

我觉得创建自己的令牌不起作用,因为WCF服务无法将其解码回声明。另外,我担心我不能使用basicHttpBinding而没有安全性。

提前谢谢!

1 个答案:

答案 0 :(得分:1)

你的故事中有一些弱点,但我会跳过它们。 (例如:如果您创建安全令牌,则 是STS。) 对于您想要做的事情,有几种方法。最标准但最困难的是对您的服务使用ws2007federationhttpbinding绑定。这需要一个支持WS-Trust协议的完整STS(带有securitytoken服务类等)。如果您的服务需要从互联网上调用并且标准很重要(比如在混合的Java / c#环境中),我会建议这种方法。

在Intranet方法中,还可以回退到将安全令牌作为数据提取的一部分传递。您在客户端上序列化claimprincipal(使用您选择的securitytokenhandler)并在您的服务中反序列化它(使用相同的安全性令牌处理程序)。根据安全要求,您可以或多或少严格遵守序列化令牌的安全性。如果它需要是安全的,您可以选择在客户端上签名,然后验证服务上的签名(使用对称密钥或基于您的偏好的证书)。

如果您希望发送的claimprincipal自动反序列化并分配给ClaimsPrincipal.Current,那么您可以考虑创建一个小的WCF服务行为,该行为将主体发送到服务并在服务中解压缩。此行为中的功能与第二种方法大致相同。这是一项更多的工作,但它是一个可重用的解决方案。如果你在这种行为上走得太远,那么解决方案1是一种更好的方法。

作为最后的评论。如果你想&#34;检查索赔&#34;然后你想迁移想要使用ClaimsAuthorizationManager而不是服务来做到这一点。在这种情况下,您不需要通过电汇传递任何ClaimsPrincipal。