如何将WCF UserName clientCredentialType传递给其他服务?

时间:2009-04-21 08:03:53

标签: c# wcf web-services security

我在同一主机上的IIS6中托管了几个WCF服务(不应该影响这个问题),我希望,由于性能/维护和其他原因,使用Facade Service将多个请求合并为1个请求, 所有这些都是通过特殊的服务合同/服务完成的,该服务合同/服务的操作可以调用其他服

我正在使用带有Message安全性和UserName客户端凭据类型的WSHTTP(可能在不久的将来使用BasicHttp)。

我希望Facade Service使用来自客户端的凭据。这意味着对后端服务的调用将获得凭证,就好像客户端将直接调用它一样。

例如: 客户端使用UserName“A”和密码“B”调用FacadeService.CompositeOperation。 现在,FacadeService.CompositeOperation需要调用BackEndService.BackendOperation,将Credentials.UserName.UserName设置为“A”,将Credentials.UserName.Password设置为“B”,就像客户端在调用此操作时所做的那样。我无法在WCF中提取此信息(它应该是,因为它是敏感信息)但我既没有找到一种方法来获取这些信息的“令牌”并将其传递给后端服务(我没有必要在FacadeService中知道这些信息,只传递它们。

在FacadeService中,与BackEndService一样,身份验证是通过ASP.NET提供程序进行的,授权是从PrimaryIdentity获取UserName的自定义基于角色的授权,因此BackEndService上的PrimaryIdentity应设置为客户端发送的内容

我该怎么做?

2 个答案:

答案 0 :(得分:0)

我昨天看了你的帖子,但不确定答案,但看到你没有回复,我以为我会添加一些东西,也许会提供一些思考的东西。

  • 首先,是否会使附加服务调用对资源过度密集?如果没有,那么代码清晰度存在争议,将它们分开,以便将来开发人员将确切知道发生了什么,而不是执行多个操作的1个服务调用。

  • 您是否无法从您正在使用的方法中调用服务器端代码中的其他服务?曾经,你是服务器端,安全上下文应该保存你所使用的用户的身份,因此对其他服务的调用将使用相同的身份。

  • 最后,我想知道是否可以在服务器上使用WCF模拟(MSDN LINK)来实现您所追求的目标。我自己没有使用它,所以不能像我想的那样建议。

希望有所帮助 - 祝你好运!

答案 1 :(得分:0)

我试图在PrimaryIdentity中将密码与UserName一起存储。 为此,我们需要做的是提供一个新的UserNameSecurityTokenAuthenticator,它将验证UserName和Password,然后可以存储在Identity中,然后它将Identity存储在WCF的SecurityContext中。

要做的步骤

课程

1。)TestServiceHost:ServiceHost

2。)UserNamePasswordSecurityTokenManager:ServiceCredentialsSecurityTokenManager

3。)TestUserNameSecurityTokenAuthenticator:UserNameSecurityTokenAuthenticator

4。)MyIdentity:IIdentity

5.。)MyAuthorizatoinPolicy:IAuthorizationPolicy

1。)创建新的ServiceHost类TestServiceHost

2.。)在TestServiceHost中覆盖OnOpening并提供一个新的类UserNamePasswordServiceCredentials

protected override void OnOpening()
{
    base.OnOpening();
    this.Description.Behaviors.Add(new UserNamePasswordServiceCredentials());
}

3.)然后在UserNamePasswordServiceCredentials中,提供新的UserNamePasswordSecurityTokenManager

public override SecurityTokenManager CreateSecurityTokenManager()
{
    return new UserNamePasswordSecurityTokenManager(this);
}

4.)然后在UserNamePasswordSecurityTokenManager中提供新的TestUserNameSecurityTokenAuthenticator

public override SecurityTokenAuthenticator CreateSecurityTokenAuthenticator(SecurityTokenRequirement tokenRequirement, out SecurityTokenResolver outOfBandTokenResolver)
        {
            if (tokenRequirement.TokenType == SecurityTokenTypes.UserName)
            {
                outOfBandTokenResolver = null;
                return new TestUserNameSecurityTokenAuthenticator();
            }
            return base.CreateSecurityTokenAuthenticator(tokenRequirement, out outOfBandTokenResolver);
        }

5.)然后在TestUserNameSecurityTokenAuthenticator内,您可以验证UseraName和密码,并可以创建自己的身份。在此函数中,您将返回要评估的IAuthorization策略列表。我创建了自己的授权策略并将新身份传递给它,以便在上下文中设置身份。

protected override System.Collections.ObjectModel.ReadOnlyCollection<System.IdentityModel.Policy.IAuthorizationPolicy> ValidateUserNamePasswordCore(string userName, string password)
        {           
            ClaimSet claimSet = new DefaultClaimSet(ClaimSet.System, new Claim(ClaimTypes.Name, userName, Rights.PossessProperty));
            List<IIdentity> identities = new List<IIdentity>(1);
            identities.Add(new MyIdentity(userName,password));
            List<IAuthorizationPolicy> policies = new List<IAuthorizationPolicy>(1);
            policies.Add(new MyAuthorizationPolicy(ClaimSet.System, identities));
            return policies.AsReadOnly();
        }


public class MyAuthorizationPolicy : IAuthorizationPolicy
    {
        String id = Guid.NewGuid().ToString();
        ClaimSet issuer;
        private IList<IIdentity> identities;
        #region IAuthorizationPolicy Members


        public MyAuthorizationPolicy(ClaimSet issuer, IList<IIdentity> identities)
        {
            if (issuer == null)
                throw new ArgumentNullException("issuer");
            this.issuer = issuer;
            this.identities = identities;

        }

        public bool Evaluate(EvaluationContext evaluationContext, ref object state)
        {
            if (this.identities != null)
            {
                object value;
                IList<IIdentity> contextIdentities;
                if (!evaluationContext.Properties.TryGetValue("Identities", out value))
                {
                    contextIdentities = new List<IIdentity>(this.identities.Count);
                    evaluationContext.Properties.Add("Identities", contextIdentities);
                }
                else
                {
                    contextIdentities = value as IList<IIdentity>;
                }
                foreach (IIdentity identity in this.identities)
                {
                    contextIdentities.Add(identity);
                }
            }
            return true;
        }

        public ClaimSet Issuer
        {
            get { return this.issuer; }
        }

        #endregion

        #region IAuthorizationComponent Members

        public string Id
        {
            get { return this.id; }
        }

        #endregion
    }

因此,此示例显示了如何在WCF中覆盖安全性:

现在问题在于:

1。)实施此技术并在您的身份中设置用户名和密码。现在,当您有呼叫子服务时,从中获取身份提取用户名和密码并传递给子服务。

2。)验证UserName和Password并为其生成令牌(应为此创建新的令牌服务)。将此令牌与用户名一起保存在您的标识中,并将这两个标记传递给您的子服务。现在,为了使这种方法起作用,子服务必须验证您新生成的令牌,您应该拥有令牌服务,该服务可以通过验证用户名和密码来创建令牌,还可以使用用户名验证令牌。

我个人会选择方法2,但会引入新的开销。