【问题标题】:Can a custom UserNamePasswordValidator be used as a role provider?自定义 UserNamePasswordValidator 可以用作角色提供者吗?
【发布时间】:2011-04-03 01:33:28
【问题描述】:

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

我想稍后在 PrincipalPermissionAttribute 要求中使用这些服务方法,例如:

[OperationContract]
[PrincipalPermission(SecurityAction.Demand, Role = "System Administrator")]
public string HelloWorld()
{ /* ... */ }

【问题讨论】:

  • 罗杰,你解决了这个问题吗?我也想做同样的事情。

标签: wcf wcf-security


【解决方案1】:

我认为它不能,因为您需要创建自定义主体。我认为您不能在验证器中执行此操作的原因是因为我在某处读到验证器在与操作上下文不同的线程中运行。我从未检查过它,但让我们假设它确实如此。基于此假设验证器中设置的 Principal 将不会用于 WCF 操作。您必须创建custom autorization 或自定义角色提供者。

【讨论】:

    【解决方案2】:

    扩展拉迪斯拉夫的回答:

    没有。自定义 UserNamePasswordValidator 不能用作角色提供者。 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 以返回从 ServiceCredentialsSecurityTokenManager 派生的 MySecurityTokenManager。对此,覆盖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")]
    

    【讨论】:

    猜你喜欢
    • 2017-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-01
    • 2010-10-20
    相关资源
    最近更新 更多