【问题标题】:WCF Custom Authentication IssueWCF 自定义身份验证问题
【发布时间】:2016-02-03 04:20:46
【问题描述】:

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

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

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

问题:

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

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

谢谢,

内存

【问题讨论】:

  • 我编辑了我的帖子,向您展示 OperationContext/GenericContext 代码。希望有用

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


【解决方案1】:

1.连接的基本解决方案

可能是最快且最简单的方法是在 用户名标题并创建一个CustomValidator。

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

2。有一些方法可以传递一些**额外的标头,并使用OperationContext.**

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

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

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

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

传递额外的标题:

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

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

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 中查找“Context bindings as custom context”以获得 GenericContext 类 如果你花时间在 WCF 上,他的书很棒

问候

【讨论】:

  • 谢谢。将与变量串联。
  • 好的。所以我也尝试了另一种方式。删除了CustomValidator。实现了 OperationContext 并在额外的标头中传递了变量。但是如何将用户信息与当前请求联系起来。如何以这种方式实现自定义原则和身份。
  • 根据 Löwy 的说法,您可以将任何作为 DataContract 的 T 传递给 GenericContext
  • @ram,我刚刚对我的帖子的第 2 部分进行了重大编辑以回答您的评论。现在还有一个 VS 解决方案的链接
  • @ram - 错误错误!抱歉,我忘了提交我的修改。他们张贴在这里
猜你喜欢
  • 1970-01-01
  • 2010-11-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多