在WCF中进行自定义用户名密码验证的最佳方法是什么?

时间:2011-05-04 10:29:03

标签: wcf passwords username validation

我有以下代码(基于网上的大量示例)

public class UserNameValidator : UserNamePasswordValidator
{
    /// <summary>
    /// Validates the user name and password combination.
    /// </summary>
    /// <param name="userName">The user name.</param>
    /// <param name="password">The password.</param>
    public override void Validate(string userName, string password)
    {
        // validate arguments
        if (string.IsNullOrEmpty(userName))
            throw new ArgumentNullException("userName");
        if (string.IsNullOrEmpty(password))
            throw new ArgumentNullException("password");

        UserCredential user = InMemoryUserStore.Get(userName);
        if (user == null)
        {
            using (DataAccessAdapter da = new DataAccessAdapter())
            {
                LinqMetaData db = new LinqMetaData(da);
                var newUserCredential = (from u in db.User
                                         where u.Username == userName
                                         select new UserCredential
                                         {
                                             UserName = u.Username,
                                             PasswordHash = u.PasswordHash,
                                             PasswordSalt = u.PasswordSalt
                                         }).FirstOrDefault();
                if (newUserCredential == null)
                {
                    throw new SecurityTokenException("Unknown username or password");
                }
                else
                {
                    InMemoryUserStore.Add(newUserCredential);
                    user = newUserCredential;
                }
            }
        }

        //Validate Password
        PasswordHash p = new PasswordHash(user.PasswordSalt, user.PasswordHash);
        if (!p.Verify(password))
        {
            throw new SecurityTokenException("Unknown username or password");
        }
    }
}

这是最好的方式吗?

1 个答案:

答案 0 :(得分:1)

看到自定义验证器只调用一次,不需要InMemoryStore。下面的代码就是我们正在使用的代码,它在生产中运行良好。

    public override void Validate(string userName, string password)
    {
        // validate arguments
        if (string.IsNullOrEmpty(userName))
            throw new ArgumentNullException("userName");
        if (string.IsNullOrEmpty(password))
            throw new ArgumentNullException("password");

        using (DataAccessAdapter da = new DataAccessAdapter())
        {
            LinqMetaData db = new LinqMetaData(da);
            var userCredential = (from u in db.User
                                  where u.Username == userName
                                  select new UserCredential
                                  {
                                      UserName = u.Username,
                                      PasswordHash = u.PasswordHash,
                                      PasswordSalt = u.PasswordSalt
                                  }).FirstOrDefault();
            if (userCredential == null)
            {
                throw new SecurityTokenException("Unknown username or password");
            }

            //Validate Password
            PasswordHash p = new PasswordHash(userCredential.PasswordSalt, userCredential.PasswordHash);
            if (!p.Verify(password))
            {
                throw new SecurityTokenException("Unknown username or password");
            }
        }
    }

通过身份验证后,您可以使用以下命令创建自定义主体:

public bool Evaluate(EvaluationContext evaluationContext, ref object state)
    {
        // get the authenticated client identity
        IIdentity client = GetClientIdentity(evaluationContext);            

        // add roles etc
        ....

        evaluationContext.Properties["Principal"] = new CustomPrincipal(client, roles.ToArray(), userId, email, client.Name);

        return true;
    }