ASP.NET会员资格提供程序 - 重置密码功能 - 电子邮件确认和密码更改

13

有没有人能提供以下功能的解决方案(示例代码):

  • 创建一个随机Guid/具有密码学强度的随机数
  • 将包含该随机数的唯一URL发送到用户的电子邮件地址
  • 确认后,要求用户更改密码

我的服务提供商目前是这样参数化的:

enablePasswordRetrieval="false" 
enablePasswordReset="true" 
requiresQuestionAndAnswer="false" 
applicationName="/" 
requiresUniqueEmail="true" 
passwordFormat="Hashed" 
maxInvalidPasswordAttempts="5" 
minRequiredPasswordLength="5" 
minRequiredNonalphanumericCharacters="0" 
passwordAttemptWindow="10" 
passwordStrengthRegularExpression="" 
name="AspNetSqlMembershipProvider"

此类过程的安全问题曾在此处讨论。


请查看System.Security.Cryptography中的加密随机数生成器提供程序以生成您的随机数,并使用简单的映射将它们转换为字母数字字符 - 全部小写,跳过字母i,l和o以避免混淆(也可以跳过所有元音字母以避免不良词语)。将电子邮件地址和随机密钥存储在数据库中,并创建一个简单的页面来捕获新密码等信息,并使用密钥查找用户,然后调用user.ChangePassword(mu.ResetPassword(), password)来更改密码。 - Neal
1
你可以在http://www.4guysfromrolla.com/articles/062508-1.aspx上找到详细的好解决方案。 - AmirHossein
2个回答

5
Rui,几个月前我也面临类似的问题,在之前没有接触过会员提供程序的情况下,我很难正确地实现它,因为我认为你必须完整地实现和使用它,否则就什么都不行。
但我很快发现,你只能使用其中的一部分,而不是整个对象。例如,在我的应用程序中,我有自己的用户对象和自己的密码和登录模块,但我需要让表单身份验证起作用。所以我基本上只是使用会员提供程序的这一部分。我没有覆盖任何方法或其他内容,只是将其用于FormsAuthentication,然后使用自己的存储库来更改密码、验证用户名密码等。
以下是我在MVC中的登录代码片段。
   var authTicket =  new FormsAuthenticationTicket(1, user.UniqueName, DateTime.UtcNow, DateTime.UtcNow.AddHours(2), rememberMe, cookieValues);
    var encryptedTicket = FormsAuthentication.Encrypt(authTicket);
    var authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket) { Expires = DateTime.UtcNow.AddDays(14) };

    httpResponseBase.Cookies.Add(authCookie);

这使我能够使用FormsAuthentication.SignOut();方法以及其他会员提供的方法。
关于创建一个随机的Guid/密码强度随机数的问题,这里有一个不错的方法,我之前找到过,但是很抱歉我不能记得在网上的具体位置。
/// <summary>
/// A simple class which can be used to generate "unguessable" verifier values.
/// </summary>
public class UnguessableGenerator
{
    const string AllowableCharacters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789/^()";
    const string SimpleAllowableCharacters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

    /// <summary>
    /// Generates an unguessable string sequence of a certain length
    /// </summary>
    /// <param name="length">The length.</param>
    /// <param name="useSimpleCharacterSet">if set to <c>true</c> [use simple character set].</param>
    /// <returns></returns>
    public static string GenerateUnguessable(int length, bool useSimpleCharacterSet = false, string additionalCharacters = "")
    {
        var random = new Random();

        var chars = new char[length];

        var charsToUse = useSimpleCharacterSet ? SimpleAllowableCharacters : AllowableCharacters;
        charsToUse = string.Format("{0}{1}", charsToUse, additionalCharacters);

        var allowableLength = charsToUse.Length;

        for (var i = 0; i < length; i++)
        {
            chars[i] = charsToUse[random.Next(allowableLength)];
        }

        return new string(chars);
    }




    /// <summary>
    /// Generates an ungessable string, defaults the length to what google uses (24 characters)
    /// </summary>
    /// <returns></returns>
    public static string GenerateUnguessable()
    {
        return GenerateUnguessable(24);
    }
}

为了向用户发送包含随机数的唯一链接,您需要在用户表或任何表中存储一个随机ID,并将其用于电子邮件中的构建URL,以供用户验证。

这将要求您创建一个接受此类URL的URL,然后从查询字符串中提取所需部分并更新用户对象。

当确认后,系统会要求用户更改密码。在您的表中默认有一个比特标志,用于强制用户更改密码,如果您需要强制用户更改密码,则此功能非常有用。因此,您的登录代码将查看该比特标志是否打开,如果是,则首先强制用户更改密码。一旦用户更改了密码,您将关闭此标志。

希望这可以帮助您。


2
因为代码示例中滥用了Thread.Sleep,所以被踩了 - 如果你想要真正的随机数据,请使用加密随机数生成器提供程序。 - Neal
好的,已经删掉了。一旦你允许竞态条件,你会意识到没有真正的随机数据。 - Ryk
使用Guid,为什么要费这么大的劲去跳转呢?因为Guid保证是唯一的。 - Eric Brown - Cal

1

至少使用Guid类来生成GUID。您可以自定义结果

var guid = Guid.NewGuid();

发送链接

var msg = new MailMessage();
msg.From = new MailAddress("YOUR_ADDRESS");
msg.To.Add(new MailAddress("CLIENT_ADDRESS"));
msg.Subject = "YOUR SUBJECT";
msg.Body = @" SOME TXT.... http:\\resetPassword.aspx?guid=" + guid;
var smtpClient = new SmtpClient("SMTP_SERVER", 9990);
smtpClient.Send(msg);

.....

之后,您只需像resetPassword.aspx一样创建一个网页,并在页面加载中处理参数“guid”,它应该链接到数据库中的用户


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接