ASP.NET标识:生成随机密码

时间:2015-02-12 14:34:26

标签: c# asp.net asp.net-mvc

是否有任何内置函数可以创建随机密码? Asp.net简单的memebership曾经有类似的方法

6 个答案:

答案 0 :(得分:14)

虽然我在派对上有点晚了,但我想分享一下帮助方法,我把它放在一起以ASP.NET Core兼容的方式处理这些场景。

下面的函数确保了一个合适的char分布,在字符串中随机添加所需的字符类型,而不是改变所需的长度(除非边缘情况具有许多所需的唯一字符,这是设计意味着的)。它还支持RequiredUniqueChars规则,这是 ASP.NET核心身份 框架可用的强度要求之一。

    /// <summary>
    /// Generates a Random Password
    /// respecting the given strength requirements.
    /// </summary>
    /// <param name="opts">A valid PasswordOptions object
    /// containing the password strength requirements.</param>
    /// <returns>A random password</returns>
    public static string GenerateRandomPassword(PasswordOptions opts = null)
    {
        if (opts == null) opts = new PasswordOptions()
        {
            RequiredLength = 8,
            RequiredUniqueChars = 4,
            RequireDigit = true,
            RequireLowercase = true,
            RequireNonAlphanumeric = true,
            RequireUppercase = true
        };

        string[] randomChars = new[] {
            "ABCDEFGHJKLMNOPQRSTUVWXYZ",    // uppercase 
            "abcdefghijkmnopqrstuvwxyz",    // lowercase
            "0123456789",                   // digits
            "!@$?_-"                        // non-alphanumeric
        };

        Random rand = new Random(Environment.TickCount);
        List<char> chars = new List<char>();

        if (opts.RequireUppercase)
            chars.Insert(rand.Next(0, chars.Count), 
                randomChars[0][rand.Next(0, randomChars[0].Length)]);

        if (opts.RequireLowercase)
            chars.Insert(rand.Next(0, chars.Count), 
                randomChars[1][rand.Next(0, randomChars[1].Length)]);

        if (opts.RequireDigit)
            chars.Insert(rand.Next(0, chars.Count), 
                randomChars[2][rand.Next(0, randomChars[2].Length)]);

        if (opts.RequireNonAlphanumeric)
            chars.Insert(rand.Next(0, chars.Count), 
                randomChars[3][rand.Next(0, randomChars[3].Length)]);

        for (int i = chars.Count; i < opts.RequiredLength
            || chars.Distinct().Count() < opts.RequiredUniqueChars; i++)
        {
            string rcs = randomChars[rand.Next(0, randomChars.Length)];
            chars.Insert(rand.Next(0, chars.Count), 
                rcs[rand.Next(0, rcs.Length)]);
        }

        return new string(chars.ToArray());
    }

该函数将PasswordOptions对象作为参数,由Microsoft.AspNetCore.Identity程序集提供,但您可以使用两个int / four bool 参数组轻松替换它(或POCO类)如果您没有安装该软件包。

在您可能的情况下,在ASP.NET Core项目中,您可以在定义密码要求时使用 Startup 类的ConfigureService方法中使用的完全相同的对象:

[...]

// Add ASP.NET Identity support
services.AddIdentity<ApplicationUser, IdentityRole>(
    opts =>
    {
        opts.Password.RequireDigit = true;
        opts.Password.RequireLowercase = true;
        opts.Password.RequireUppercase = true;
        opts.Password.RequireNonAlphanumeric = false;
        opts.Password.RequiredLength = 7;
    })
    .AddEntityFrameworkStores<ApplicationDbContext>();

[...]

有关此帮助程序功能的其他详细信息,您还可以在我的博客上read this post

答案 1 :(得分:11)

您使用的是哪种框架?

检查here

 string password = Membership.GeneratePassword(12, 1);

答案 2 :(得分:8)

ASP.NET Identity没有生成密码方法。

我不确定您的确切用例,但我认为首选方法是向用户发送重置密码链接,允许用户输入自己的密码。这通常被认为比以纯文本形式发送生成的密码更安全。

请参阅本教程中的“重置密码”部分: http://www.asp.net/identity/overview/features-api/account-confirmation-and-password-recovery-with-aspnet-identity

答案 3 :(得分:3)

Membership.GeneratePassword() create a password that isn't compliant with Identity validator.

I have written a simple function that consider UserManager Validator for creating a right random password to assign to user.

It simply generates random chars and check if chars satisfy Validator requirements. If the requirements aren't satisfied, it appends the remaining chars to satisfy rules.

private string GeneratePassword(MessagePasswordValidator validator)
{
    if (validator == null)
        return null;

    bool requireNonLetterOrDigit = validator.RequireNonLetterOrDigit;
    bool requireDigit = validator.RequireDigit;
    bool requireLowercase = validator.RequireLowercase;
    bool requireUppercase = validator.RequireUppercase;

    string randomPassword = string.Empty;

    int passwordLength = validator.RequiredLength;

    Random random = new Random();
    while (randomPassword.Length != passwordLength)
    {
        int randomNumber = random.Next(48, 122);  // >= 48 && < 122 
        if (randomNumber == 95 || randomNumber == 96) continue;  // != 95, 96 _'

        char c = Convert.ToChar(randomNumber);

        if (requireDigit)
            if (char.IsDigit(c))
                requireDigit = false;

        if (requireLowercase)
            if (char.IsLower(c))
                requireLowercase = false;

        if (requireUppercase)
            if (char.IsUpper(c))
                requireUppercase = false;

        if (requireNonLetterOrDigit)
            if (!char.IsLetterOrDigit(c))
                requireNonLetterOrDigit = false;

        randomPassword += c;
    }

    if (requireDigit)
        randomPassword += Convert.ToChar(random.Next(48, 58));  // 0-9

    if (requireLowercase)
        randomPassword += Convert.ToChar(random.Next(97, 123));  // a-z

    if (requireUppercase)
        randomPassword += Convert.ToChar(random.Next(65, 91));  // A-Z

    if (requireNonLetterOrDigit)
        randomPassword += Convert.ToChar(random.Next(33, 48));  // symbols !"#$%&'()*+,-./

    return randomPassword;
}

and calling:

string password = GeneratePassword(UserManager.PasswordValidator as MessagePasswordValidator);

答案 4 :(得分:2)

我知道这是一个老问题,而且还有其他人为了随机生成密码而推出了源代码 Membership.GeneratePassword的实现方式如下:

幸运的是,这是根据麻省理工学院许可证https://github.com/Microsoft/referencesource/blob/master/LICENSE.txt

获得许可的
public class PasswordStore
{
        private static readonly char[] Punctuations = "!@#$%^&*()_-+=[{]};:>|./?".ToCharArray();
        private static readonly char[] StartingChars = new char[] { '<', '&' };
        /// <summary>Generates a random password of the specified length.</summary>
        /// <returns>A random password of the specified length.</returns>
        /// <param name="length">The number of characters in the generated password. The length must be between 1 and 128 characters. </param>
        /// <param name="numberOfNonAlphanumericCharacters">The minimum number of non-alphanumeric characters (such as @, #, !, %, &amp;, and so on) in the generated password.</param>
        /// <exception cref="T:System.ArgumentException">
        /// <paramref name="length" /> is less than 1 or greater than 128 -or-<paramref name="numberOfNonAlphanumericCharacters" /> is less than 0 or greater than <paramref name="length" />. </exception>
        public static string GeneratePassword(int length, int numberOfNonAlphanumericCharacters)
        {
            if (length < 1 || length > 128)
                throw new ArgumentException("password_length_incorrect", nameof(length));
            if (numberOfNonAlphanumericCharacters > length || numberOfNonAlphanumericCharacters < 0)
                throw new ArgumentException("min_required_non_alphanumeric_characters_incorrect", nameof(numberOfNonAlphanumericCharacters));
            string s;
            int matchIndex;
            do
            {
                var data = new byte[length];
                var chArray = new char[length];
                var num1 = 0;
                new RNGCryptoServiceProvider().GetBytes(data);
                for (var index = 0; index < length; ++index)
                {
                    var num2 = (int)data[index] % 87;
                    if (num2 < 10)
                        chArray[index] = (char)(48 + num2);
                    else if (num2 < 36)
                        chArray[index] = (char)(65 + num2 - 10);
                    else if (num2 < 62)
                    {
                        chArray[index] = (char)(97 + num2 - 36);
                    }
                    else
                    {
                        chArray[index] = Punctuations[num2 - 62];
                        ++num1;
                    }
                }
                if (num1 < numberOfNonAlphanumericCharacters)
                {
                    var random = new Random();
                    for (var index1 = 0; index1 < numberOfNonAlphanumericCharacters - num1; ++index1)
                    {
                        int index2;
                        do
                        {
                            index2 = random.Next(0, length);
                        }
                        while (!char.IsLetterOrDigit(chArray[index2]));
                        chArray[index2] = Punctuations[random.Next(0, Punctuations.Length)];
                    }
                }
                s = new string(chArray);
            }
            while (IsDangerousString(s, out matchIndex));
            return s;
        }

        internal static bool IsDangerousString(string s, out int matchIndex)
        {
            //bool inComment = false;
            matchIndex = 0;

            for (var i = 0; ;)
            {

                // Look for the start of one of our patterns 
                var n = s.IndexOfAny(StartingChars, i);

                // If not found, the string is safe
                if (n < 0) return false;

                // If it's the last char, it's safe 
                if (n == s.Length - 1) return false;

                matchIndex = n;

                switch (s[n])
                {
                    case '<':
                        // If the < is followed by a letter or '!', it's unsafe (looks like a tag or HTML comment)
                        if (IsAtoZ(s[n + 1]) || s[n + 1] == '!' || s[n + 1] == '/' || s[n + 1] == '?') return true;
                        break;
                    case '&':
                        // If the & is followed by a #, it's unsafe (e.g. &#83;) 
                        if (s[n + 1] == '#') return true;
                        break;
                }

                // Continue searching
                i = n + 1;
            }
        }

        private static bool IsAtoZ(char c)
        {
            if ((int)c >= 97 && (int)c <= 122)
                return true;
            if ((int)c >= 65)
                return (int)c <= 90;
            return false;
        }
    }

答案 5 :(得分:-6)

https://msdn.microsoft.com/ru-ru/library/system.guid.newguid(v=vs.110).aspx 看一下这个。 GUID应该可以正常工作(只需删除所有&#39; - &#39;并删除所需的数字,如果是字符)