简体   繁体   English

WCF自定义身份验证问题

[英]WCF Custom Authentication Issue

I have implemented Custom Authentication with UserNamePasswordValidator. 我已经使用UserNamePasswordValidator实现了自定义身份验证。

According to project requirement, I require four input parameters for authentication(Username, Password, SiteID, BrandID). 根据项目要求,我需要四个输入参数进行身份验证(用户名,密码,SiteID,BrandID)。

But Validate Method accept only two parameters: Validate(string userName, string password) 但是Validate方法仅接受两个参数:Validate(字符串userName,字符串密码)

Question: 题:

1) How can I send more than two parameters to Validate Method? 1)如何向验证方法发送两个以上的参数?

2) Is there any other approach to define WCF Authentication with own validate methods? 2)是否有其他方法可以使用自己的验证方法来定义WCF身份验证?

Thank You, 谢谢,

Ram 内存

1. Basic solution with concatenation 1.串联的基本解决方案

May be the fastest way and easiest is to concatenate Username, SiteID, and BrandID (separated with / or - and making some kind of escapes to prevent use of separation characters) in the Username header and create a CustomValidator. 最快,最简单的方法可能是在Username标头中 串联Username,SiteID和BrandID (用/或-分隔,并进行某种转义以防止使用分隔符),然后创建CustomValidator。

--------------------------- Edit --------------------------- --------------------------- 编辑 ---------------------- -----

2. There are some ways to pass some **extra headers , and use OperationContext .** 2.有一些方法可以传递一些** extra标头 ,并使用OperationContext 。**

I'll also show how to put declarative permissions 我还将展示如何放置声明性权限

In order to do that, you can use classes of Juval Löwy. 为此,您可以使用JuvalLöwy类。 He implements a GenericContext<T> you can use. 他实现了您可以使用的GenericContext<T>

GenericContext<T> encapsulates the mechanics of accessing headers. GenericContext<T>封装了访问标头的机制。

2.1 Create a shared Library 2.1创建共享库

To share some data from client and server, passed as soap headers 共享来自客户端和服务器的一些数据,作为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 On the client side 2.2在客户端

Pass the extra 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();
} 

The proxy has to be changed a bit (not Visual Studio or svcutil.exe generation): 必须稍微更改代理(不是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 - Add declarative permission on the server side 2.3-在服务器端添加声明性权限

Declarative permission with the 具有
[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 Add a serviceAuthorizationBehavior to stick an identity to the use 2.4添加serviceAuthorizationBehavior来保留身份

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

2.5 Implement the serviceAuthorizationBehvior 2.5实现serviceAuthorizationBehvior

The goal of that behavior is to assign a Principal and an identity to the caller. 该行为的目标是为调用者分配一个主体和一个身份。

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 The CustomPrincipal class takes care of putting the user in a role 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);
    }
}

Conclusion 结论

Behind the scenes, Juval's classes read(server side) and write(client side) header. 在后台,Juval的类具有read(服务器端)和write(客户端)头。

Excerpt, for instance : 摘录,例如:

     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 to full working source code : http://1drv.ms/1OqPMUM 链接到完整的工作源代码: http : //1drv.ms/1OqPMUM

Link to excellent Juval Lowy's code : Look for "Context bindings as custom context" in the page http://www.idesign.net/Downloads to have the GenericContext class His book is great if you spend time on WCF 链接到出色的Juval Lowy的代码:在http://www.idesign.net/Downloads页面上查找“将上下文绑定作为自定义上下文”,以获取GenericContext类。如果您花时间在WCF上,他的书很棒。

Regards 问候

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM