WCF 自定义验证器:如何初始化“用户”验证器来自自定义验证器的对象

发布于 2024-08-23 00:22:15 字数 957 浏览 9 评论 0原文

我有一个工作自定义 UserNamePasswordValidator 可以调用我的 Oracle DB。

此类派生自 System.IdentityModel.Selectors.UserNamePasswordValidator,并且 Validate() 方法返回 void。

我从数据库加载我的用户对象,一旦验证了密码,我想隐藏我的“用户”对象,以便服务在处理其业务时可以访问它。在 ASP.NET/Java 领域,我会将其存储到会话中,或者可能是我的整个控制器类中。如何从 WCF 中的验证器执行此操作?

或者,换句话说,WCF 领域为服务设置自定义用户域对象的最佳实践是什么。

更新:这就是我解决这个问题的方法。我在验证器期间缓存 User 对象,然后在 AuthorizatinPolicy 步骤中访问它。

  // this gets called after the custom authentication step where we loaded the User
  public bool Evaluate(EvaluationContext evaluationContext, ref object state)
  {
     // get the authenticated client identity
     IIdentity client = GetClientIdentity(evaluationContext);

     User user;
     OraclePasswordValidator.users.TryGetValue(client.Name, out user);
     if(user != null) {
        // set the custom principal
        evaluationContext.Properties["Principal"] = user;
        return true;
     }

     return false;
  }

I have a working custom UserNamePasswordValidator that calls into my Oracle DB.

This class derives from System.IdentityModel.Selectors.UserNamePasswordValidator and the Validate() method returns void.

I load my User object from the database, and once the password is validated, I want to stash my "User" object so the service can access it when going about its business. In ASP.NET / Java land I would stash it into a session, or perhaps my overall Controller class. How do I do this from the Validator in WCF?

Or, in other words, what is the best practice in WCF land to set a custom User domain object for the service.

Update: This is how I've worked around it. I cache the User object during the validator, then access it later in the AuthorizatinPolicy step.

  // this gets called after the custom authentication step where we loaded the User
  public bool Evaluate(EvaluationContext evaluationContext, ref object state)
  {
     // get the authenticated client identity
     IIdentity client = GetClientIdentity(evaluationContext);

     User user;
     OraclePasswordValidator.users.TryGetValue(client.Name, out user);
     if(user != null) {
        // set the custom principal
        evaluationContext.Properties["Principal"] = user;
        return true;
     }

     return false;
  }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

演出会有结束 2024-08-30 00:22:15

我不是 WCF 专家,但从我迄今为止阅读和实现的内容来看,执行此操作的“正确”方法是使用 Validator 进行身份验证用户,然后实现一个 IAuthorizationPolicy 来执行实际的授权。因此,您将在授权策略中在当前线程上设置自定义主体。

为了能够转发来自用户名/密码验证的信息,您可以实现一个继承自 UserNameSecurityTokenAuthenticator 的安全令牌身份验证器。 SecurityTokenAuthenticator将首先调用验证器,如果验证成功,它可以添加您的自定义授权策略并通过构造函数将用户信息发送到策略。内容很长:

public class CustomUsernameSecurityTokenAuthenticator : UserNameSecurityTokenAuthenticator
{
    protected override bool CanValidateTokenCore(System.IdentityModel.Tokens.SecurityToken token)
    {
        return (token is UserNameSecurityToken);
    }

    protected override ReadOnlyCollection<IAuthorizationPolicy> ValidateTokenCore(SecurityToken token)
    {
        var authorizationPolicies = new List<IAuthorizationPolicy>();

        try
        {
            var userNameToken = token as UserNameSecurityToken;
            new CustomUserNameValidator().Validate(userNameToken.UserName, userNameToken.Password);

            var claims = new DefaultClaimSet(ClaimSet.System, new Claim(ClaimTypes.Name, userNameToken.UserName, Rights.PossessProperty));

            authorizationPolicies.Add(new CustomAuthorizationPolicy(claims));
        }
        catch (Exception)
        {
            authorizationPolicies.Add(new InvalidAuthorizationPolicy());
            throw;
        }
        return authorizationPolicies.AsReadOnly();
    }
}

这里有一篇文章对所涉及的类进行了更多描述; http://blogs.msdn.com/card/archive/2007/10/04/how-identity-providers-can-show-custom-error-messages-in-cardspace.aspx

I'm not a WCF expert, but from what I've read and implemented so far, the 'correct' way to do this would be to use the Validator to authenticate the user, and then implement an IAuthorizationPolicy to do the actual authorization. So it would be in the authorization policy that you'll set your custom principal on the current thread.

To be able to forward information from the username/password validation, you can implement a security token authenticator that inherits from UserNameSecurityTokenAuthenticator. The SecurityTokenAuthenticator will first call the validator and if validation succeeds, it can add your custom authorization policy and send userinfo to the policy through the constructor. Something a long the lines of this:

public class CustomUsernameSecurityTokenAuthenticator : UserNameSecurityTokenAuthenticator
{
    protected override bool CanValidateTokenCore(System.IdentityModel.Tokens.SecurityToken token)
    {
        return (token is UserNameSecurityToken);
    }

    protected override ReadOnlyCollection<IAuthorizationPolicy> ValidateTokenCore(SecurityToken token)
    {
        var authorizationPolicies = new List<IAuthorizationPolicy>();

        try
        {
            var userNameToken = token as UserNameSecurityToken;
            new CustomUserNameValidator().Validate(userNameToken.UserName, userNameToken.Password);

            var claims = new DefaultClaimSet(ClaimSet.System, new Claim(ClaimTypes.Name, userNameToken.UserName, Rights.PossessProperty));

            authorizationPolicies.Add(new CustomAuthorizationPolicy(claims));
        }
        catch (Exception)
        {
            authorizationPolicies.Add(new InvalidAuthorizationPolicy());
            throw;
        }
        return authorizationPolicies.AsReadOnly();
    }
}

There's an article here that describes a bit more around the involved classes; http://blogs.msdn.com/card/archive/2007/10/04/how-identity-providers-can-show-custom-error-messages-in-cardspace.aspx

谁对谁错谁最难过 2024-08-30 00:22:15

我有完全相同的问题。

我正在使用 API 连接到底层 Oracle 数据库,并通过打开连接来“验证”登录详细信息。

然后,我想将此连接存储在某个地方(很简单,我将为所有不同的用户创建一个连接池),但也创建一个代表该用户的自定义身份和主体,这样一旦它到达我的自定义 IAuthorizationPolicy,它就不会'不需要重新加载此信息。

我已经进行了大量搜索,但没有找到任何内容,因此我的计划是这样做:

  1. 通过打开 API 连接来验证自定义 UserNamePasswordValidator 中的登录详细信息。

  2. 将打开的连接存储在用户名下的连接池中。

  3. 当调用我的自定义 IAuthorizationPolicy.Evaluate() 时,我将查看提供的通用身份:

    IIdentity GetClientIdentity(EvaluationContext 评估上下文)
    {
        对象 obj;
        if (!evaluationContext.Properties.TryGetValue("Identities", out obj))
            抛出新的异常(“未找到身份”);
    
           IList identities = obj as IList;
           if (identities == null || identities.Count <= 0)
              抛出新的异常(“未找到身份”);
    
           返回身份[0];
       }
    

抱歉,我无法摆脱这个糟糕的 HTML 转义)

  1. 然后我获取一个连接从基于 IIdentity.Name 的池中,使用此连接从数据库加载特定于用户的数据,并将其存储在我在评估上下文中设置的自定义身份和主体中:

    public bool Evaluate(EvaluationContextvaluationContext, ref 对象状态)
    {
        IIdentity 身份 = GetClientIdentity(evaluationContext);
        如果(身份==空)
            抛出新的异常();
    
            // 这些是我的自定义身份和主体类
            身份customIdentity = new Identity();
            委托人 customPrincipal = 新委托人(customIdentity);
            // 根据需要填充身份和主体
            valuationContext.Properties["Principal"] = customPrincipal;
            返回真;
        }
    

那么我应该可以在需要时使用 System.Threading.Thread.CurrentPrincipal 或 CurrentIdentity 访问我的自定义身份和主体。

希望这能在某种程度上有所帮助;我不确定这是最好的方法,但这是迄今为止我想到的最好的方法......

史蒂夫

I have exactly the same issue.

I am using an API to connect to my underlying Oracle Database, and I "validate" logon details by opening a connection.

I then want to store this connection somewhere (easy enough, I will create a connection pool for all the different users), but also create a custom Identity and Principal representing this user, so that once it gets to my custom IAuthorizationPolicy, it doesn't need to reload this information.

I have done a lot of searching and not found anything so my plan is to do this:

  1. Validate login details in custom UserNamePasswordValidator by opening API connection.

  2. Store opened connection in connection pool under the user name.

  3. When my custom IAuthorizationPolicy.Evaluate() is called, I will look at the generic identity provided:

    IIdentity GetClientIdentity(EvaluationContext evaluationContext)
    {
        object obj;
        if (!evaluationContext.Properties.TryGetValue("Identities", out obj))
            throw new Exception("No Identity found");
    
           IList<IIdentity> identities = obj as IList<IIdentity>;
           if (identities == null || identities.Count <= 0)
              throw new Exception("No Identity found");
    
           return identities[0];
       }
    

(sorry I can't get rid of this poor HTML escaping)

  1. I then grab a connection from the pool based on the IIdentity.Name, use this connection to load up user-specific data from the database and store this in a custom Identity and Principal which I set in the EvaluationContext:

    public bool Evaluate(EvaluationContext evaluationContext, ref object state)
    {
        IIdentity identity = GetClientIdentity(evaluationContext);
        if (identity == null)
            throw new Exception();
    
            // These are my custom Identity and Principal classes
            Identity customIdentity = new Identity();
            Principal customPrincipal = new Principal(customIdentity);
            // populate identity and principal as required
            evaluationContext.Properties["Principal"] = customPrincipal;
            return true;
        }
    

Then I should have access to my custom identity and principal whenever I need it by using System.Threading.Thread.CurrentPrincipal or CurrentIdentity.

Hope this helps in some way; I'm not sure it's the best way to go about it, but it's the best I've come up with so far...

Steve

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文