WCF自定义身份验证问题

时间:2015-11-03 05:25:07

标签: .net web-services wcf authentication restful-authentication

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

根据项目要求,我需要四个输入参数进行身份验证(用户名,密码,SiteID,BrandID)。

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

问题:

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

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

谢谢,

拉​​姆

1 个答案:

答案 0 :(得分:0)

<强> 1。连接的基本解决方案

可能是最快的方式,最简单的方法是连接用户名,SiteID和BrandID (用/或分隔 - 并进行某种转义以防止使用分隔字符)用户名标题并创建一个CustomValidator。

--------------------------- 修改 ------------ ---------------

<强> 2。有一些方法可以传递一些**额外标题,并使用OperationContext。**

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

为了做到这一点,你可以使用JuvalLöwy的课程。他实现了你可以使用的GenericContext<T>

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

2.1创建共享库

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

[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在客户端

传递额外的标题:

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 Studio svcutil.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

该行为的目标是为调用者分配Principal和Identity。

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类负责让用户担任角色

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的类读取(服务器端)和写入(客户端)头。

摘录,例如:

     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]; 
     }

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

链接到优秀的Juval Lowy的代码: 在页面http://www.idesign.net/Downloads中查找“上下文绑定作为自定义上下文”以获得GenericContext类 如果你花时间在WCF上,他的书很棒

此致