代码之家  ›  专栏  ›  技术社区  ›  Roger Lipscombe

自定义用户名密码验证程序能否用作角色提供程序?

  •  3
  • Roger Lipscombe  · 技术社区  · 14 年前

    有关 this question ,我有一个自定义的用户名密码验证器,可以登录到我们的内部API。作为登录的一部分,我可以发现用户在我们的系统中的角色。

    我想稍后在原则上使用这些服务方法的属性需求,例如:

    [OperationContract]
    [PrincipalPermission(SecurityAction.Demand, Role = "System Administrator")]
    public string HelloWorld()
    { /* ... */ }
    
    2 回复  |  直到 12 年前
        1
  •  6
  •   Roger Lipscombe    12 年前

    要扩展Ladislav的答案:

    不可以。自定义用户名密码验证程序不能用作角色提供程序。usernamepasswordvalidator在一个独立的上下文(或线程,或其他)中运行,该上下文与您要处理的operationcontext无关。

    您需要做的是实现自定义授权。我发现 this page 做这个最有用。警告:在你进入有趣的部分之前,有很多管道。

    基本上,你从 ServiceCredentials -派生类,注册于 App.config 如下:

    <serviceBehaviors>
      <behavior name="...">
        <serviceAuthorization principalPermissionMode="Custom" />
    
        <serviceCredentials type="MyNamespace.MyServiceCredentials, MyAssembly">
          <userNameAuthentication userNamePasswordValidationMode="Custom" />
    
          <serviceCertificate etc. />
        </serviceCredentials>
    

    将行为与服务关联起来。

    重写 ServiceCredentials.CreateSecurityTokenManager 归还 MySecurityTokenManager 来源于 ServiceCredentialsSecurityTokenManager . 在这一点上,超越 CreateSecurityTokenAuthenticator 返回一个 MySecurityTokenAuthenticator . 那应该来自 CustomUserNameSecurityTokenAuthenticator . 在这一点上,重写 ValidateUserNamePasswordCore . 调用基类,它将返回授权策略列表。

    在该列表中,添加一个新列表: MyAuthorizationPolicy ,实现 IAuthorizationPolicy . 在这一点上,你只需要(哈)做以下事情:

    public bool Evaluate(EvaluationContext evaluationContext, ref object state)
    {
        IList<IIdentity> identities = GetIdentities(evaluationContext);
    
        // Find the GenericIdentity with our user-name in it.
        IIdentity currentIdentity = identities.SingleOrDefault(
            i => i is GenericIdentity &&
            StringComparer.OrdinalIgnoreCase.Equals(i.Name, UserName));
        if (currentIdentity == null)
            throw new InvalidOperationException("No Identity found");
    
        // Replace the GenericIdentity with a new one.
        identities.Remove(currentIdentity);
        var newIdentity =
            new GenericIdentity(_userName, currentIdentity.AuthenticationType);
        identities.Add(newIdentity);
    
        // This makes it available as
        // ServiceSecurityContext.Current.PrimaryIdentity later.
        evaluationContext.Properties["PrimaryIdentity"] = newIdentity;
    
        // This makes it available as Thread.CurrentPrincipal.
        IPrincipal newPrincipal = new GenericPrincipal(newIdentity, _roles);
        evaluationContext.Properties["Principal"] = newPrincipal;
    
        return true;
    }
    
    private static IList<IIdentity> GetIdentities(
        EvaluationContext evaluationContext)
    {
        object identitiesProperty;
        if (!evaluationContext.Properties.TryGetValue(
            "Identities", out identitiesProperty))
        throw new InvalidOperationException("No Identity found");
    
        var identities = identitiesProperty as IList<IIdentity>;
        if (identities == null)
            throw new InvalidOperationException("No Identity found");
        return identities;
    }
    

    然后,在完成了这些工作之后,您可以用 PrincipalPermission :

    [PrincipalPermission(SecurityAction.Demand, Role = "Editor")]
    
        2
  •  2
  •   Ladislav Mrnka    14 年前

    我认为不能,因为您需要创建自定义主体。我认为您不能在验证器中这样做的原因是因为我在某个地方看到验证器在不同于操作上下文的线程中运行。我从来没有检查过它,但假设它确实检查过。基于此假设,验证程序中设置的主体将不会在WCF操作中使用。你必须创造 custom autorization 或自定义角色提供程序。