WCF 自定义身份验证问题

WCF Custom Authentication Issue

我已经使用 UserNamePasswordValidator 实现了自定义身份验证。

根据项目要求,我需要四个输入参数进行身份验证(用户名、密码、网站ID、品牌ID)。

但是 Validate 方法只接受两个参数:Validate(string userName, string password)

问题:

1) 如何向验证方法发送两个以上的参数?

2) 是否有任何其他方法可以使用自己的验证方法定义 WCF 身份验证?

谢谢,

内存

1.串联的基本解决方案

可能最快和最简单的方法是 连接用户名、站点 ID 和品牌 ID(用 / 或 - 分隔并进行某种转义以防止使用分隔符)在 Username header 中创建一个 CustomValidator.

---------------------------- 编辑 ------ --------------------

2。有一些方法可以传递一些 **extra headers,并使用 OperationContext.**

我还将展示如何放置 声明性权限

为此,您可以使用 Juval Löwy 的 classes。他实现了一个你可以使用的GenericContext<T>

GenericContext<T> 封装了访问 header 的机制。

2.1 创建共享库

从客户端和服务器共享一些数据,作为 soap 传递 headers

[DataContract]
public class ExtraHeaders
{
    [DataMember]
    public String Username { get; set; }
    [DataMember]
    public String Password { get; set; }
    [DataMember]
    public String BranchId { get; set; }
    [DataMember]
    public String SiteId { get; set; }
}

2.2客户端

传递额外的 headers:

static void Main(string[] args)
{
 // provide identity as headers
  var extraHeaders = new ExtraHeaders
  { 
        Username="manager",
        Password= "password",
        BranchId = "Branch2", 
        SiteId = "Site2" 
  };
  MyContractClient proxy = new MyContractClient(extraHeaders);

  proxy.MyMethod();

  proxy.Close();
} 

代理要改一下(不是Visual Studiosvcutil.exe代):

class MyContractClient : HeaderClientBase<IMyContract, ExtraHeaders>, IMyContract
{
   public MyContractClient(string key,string value) : base(key,value)
   {}
   public void MyMethod()
   {
      Channel.MyMethod();
   }
}

2.3 - 在服务器端添加声明权限


的声明许可 [PrincipalPermission(SecurityAction.Demand, Role = "Manager")]

class MyService : IMyContract
{
    [PrincipalPermission(SecurityAction.Demand, Role = "Manager")]
    public void MyMethod()
    {
        var extraHeaders = ExtraHeadersContext.Current;
        if (extraHeaders != null)
        {
            //Console.WriteLine("Extra headers: (BranchId:{0}, SiteId:{1}) ", extraHeaders.BranchId, extraHeaders.SiteId);
            Console.WriteLine("Service call from : {{{0}}}", extraHeaders.Username);
        }
    }
}

2.4 添加一个 serviceAuthorizationBehavior 以将身份贴在用户身上

<behaviors>
  <serviceBehaviors>
    <behavior name="customIdentificationBehavior">
      <serviceAuthorization principalPermissionMode="Custom">
        <authorizationPolicies>
          <add policyType="Security.HttpContextPrincipalPolicy,Host" />
        </authorizationPolicies>
      </serviceAuthorization>
    </behavior>

2.5 实现 serviceAuthorizationBehvior

该行为的目标是为调用者分配一个委托人和一个身份。

namespace Security
{
    public class HttpContextPrincipalPolicy : IAuthorizationPolicy
    {
        public bool Evaluate(EvaluationContext evaluationContext, ref object state)
        {
            try
            {
                var extraHeaders = ExtraHeadersContext.Current;
                if (extraHeaders != null)
                {
                    IPrincipal principal = new CustomPrincipal(
                        new GenericIdentity(extraHeaders.Username, "Custom Provider"),extraHeaders);

                    evaluationContext.Properties["Principal"] = principal;
                    // Put user here so it can be used for declarative access on methods
                    evaluationContext.Properties["Identities"] = new List<IIdentity>() { principal.Identity };
                }
                else
                {
                    SetAnonymousPrincipal(evaluationContext);
                }
            }
            catch (Exception)
            {
                SetAnonymousPrincipal(evaluationContext);
            }
            return true;
        }
    }
}

2.6 CustomPrincipal class 负责将用户置于角色

public class CustomPrincipal : IPrincipal
{
    private ExtraHeaders headers;
    private IIdentity identity;

    public CustomPrincipal(IIdentity identity, ExtraHeaders headers = null)
    {
        this.identity = identity;
        this.headers = headers;
    }
    public IIdentity Identity
    {
        get { return identity; }
    }
    public bool IsInRole(string role)
    {
        String[] roles;
        if (identity.Name == "manager")
            roles = new string[1] { "Manager" };
        else
            roles = new string[1] { "User" };
        return roles.Contains(role);
    }
}

结论

在幕后,Juval 的 class 读(服务器端)和写(客户端)header。

摘录,例如:

     if(OperationContext.Current.IncomingMessageProperties.ContainsKey(ContextMessageProperty.Name))
     {
        ContextMessageProperty contextProperty = OperationContext.Current.IncomingMessageProperties[ContextMessageProperty.Name] as ContextMessageProperty;
        if(contextProperty.Context.ContainsKey(key) == false)
        {
           return null;
        }
        return contextProperty.Context[key]; 
     }

Link 到完整的工作源代码:http://1drv.ms/1OqPMUM

Link 优秀的 Juval Lowy 代码: 在页面 http://www.idesign.net/Downloads 中查找 "Context bindings as custom context" 以获得 GenericContext class 如果你花时间在 WCF 上,他的书很棒

此致