在哪里可以找到C#示例code来实现ASP .NET MVC2密码恢复 [英] Where to find C# sample code to implement password recovery in ASP .NET MVC2

查看:359
本文介绍了在哪里可以找到C#示例code来实现ASP .NET MVC2密码恢复的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何实现MVC2应用程序重置密码?

密码使用ASP .NET成员提供散列。不使用密码恢复问题。与标准的AccountController类标准ASP .NET MVC2项目模板使用。

如果用户forgots密码,邮箱临时链接,或用新的密码应该发送到用户的电子邮件地址。

在哪里可以找到code来实现这MVC 2 C#?

堆栈溢出包含两个答案,其中讨论了有关实现此方法。没有样品code。
我用Google搜索ASP .NET MVC密码重置C#示例code下载,但还没有找到的样本code这一点。

我是新来的MVC。在哪里可以找到样本code密码恢复?这是从VS2010生成的项目模板失踪。

更新

我想这code在单2.10,但有例外:

不支持单CspParameters

在行

  des.Key = pdb.CryptDeriveKey(RC2,MD5,128,新的byte [8]);

如何在单声道运行呢?

堆栈跟踪:

  System.NotSupportedException:CspParameters不支持单
在System.Security.Cryptography.PasswordDeriveBytes.CryptDeriveKey(字符串,字符串,整数,字节[])[0x0001b]中/usr/src/redhat/BUILD/mono-2.10.2/mcs/class/corlib/System.Security.Cryptography/PasswordDeriveBytes.cs:197
在store2.Helpers.Password.En codeMessageWithPassword(字符串,字符串)< IL 0x00055,0x000f3>
在store2.Helpers.AccountHelper.GetTokenForValidation(字符串)< IL 0x00033,0x00089>
在MvcMusicStore.Controllers.AccountController.PasswordReminder(MvcMusicStore.Models.PasswordReminderModel)LT; IL 0x001ac,0x00495>
在(包装动态法)System.Runtime.CompilerServices.ExecutionScope.lambda_method(System.Runtime.CompilerServices.ExecutionScope,System.Web.Mvc.ControllerBase,对象[])LT; IL 0x00020,0x0005b>
在System.Web.Mvc.ActionMethodDispatcher.Execute(System.Web.Mvc.ControllerBase,对象[])LT; IL 0x00008,0x0001b>
在System.Web.Mvc.ReflectedActionDescriptor.Execute(System.Web.Mvc.ControllerContext,System.Collections.Generic.IDictionary`2<字符串对象>)< IL 0x00072,0x00103>
在System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod (System.Web.Mvc.ControllerContext,System.Web.Mvc.ActionDescriptor,System.Collections.Generic.IDictionary`2<string,对象&gt;)&所述的IL 0x00003,0x00019&GT;
在System.Web.Mvc.ControllerActionInvoker/<>c__DisplayClassd.<InvokeActionMethodWithFilters>b__a ()&所述的IL 0x0002d,0x00068&GT;
在System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter (System.Web.Mvc.IActionFilter,System.Web.Mvc.ActionExecutingContext,System.Func`1<System.Web.Mvc.ActionExecutedContext>) &LT; IL 0x00031,0x000b6&GT;
-------------------------------------------------- ------------------------------
版本信息:单声道运行时版本:2.10.2(压缩包周一4月18日18时57分39秒UTC 2011); ASP.NET版本:2.0.50727.1433


解决方案

下面是我的做法。在MVC中,您将有一个名为RetrievePassword一个动作,你会询问用户的电子邮件地址,并通过它在后

  [HTTPGET]
    公众的ActionResult RetrievePassword()
    {
        返回查看();
    }    [HttpPost]
    公众的ActionResult RetrievePassword(PasswordRetrievalModel模型)
    {
        如果(ModelState.IsValid)
        {
            字符串的用户名= Membership.GetUserNameByEmail(model.Email);            如果(!String.IsNullOrEmpty(用户名))
            {
                //这是发送电子邮件使用令牌(一个MD5)的辅助功能。
                NotificationsHelper.SendPasswordRetrieval(model.Email,this.ControllerContext);
            }
            其他
            {
                Trace.WriteLine(的String.Format(***警告:用户试图找回自己的密码,但使用的电子邮件地址{0}不存在于数据库中。model.Email));
             }
            返回RedirectToAction(指数,家);
        }        返回查看(模型);
    }

这是电子邮件将与重定向到<一个URL来发送href=\"http://example.com/Account/Validate?email=xxxxxxxx&token=xxxxxxxx\">http://example.com/Account/Validate?email=xxxxxxxx&token=xxxxxxxx

如果令牌是有效的电子邮件,你可能会因此他们选择一个新的密码显示密码重置形式。

所以你需要一个验证操作:

  [HTTPGET]
    [通信pressFilter]
    公众的ActionResult验证(字符串email,字符串标记)
    {
        布尔的isValid = FALSE;        如果(AccountHelper.IsTokenValid(令牌,电子邮件))
        {
            字符串的用户名= Membership.GetUserNameByEmail(电子邮件);
            如果(!String.IsNullOrEmpty(用户名))
            {
                //获取用户和批准。
                用户的MembershipUser = Membership.GetUser(用户名);
                user.IsApproved = TRUE;
                Membership.UpdateUser(用户);                的isValid = TRUE;                //由于这是一个成功的验证,验证用户的身份。
                FormsAuthentication.SetAuthCookie(用户名,虚假);
            }
            其他
            {
                的isValid = FALSE;
            }
        }        返回查看(isValid方法);
    }

下面是一些你在这个code看到佣工:

帐户助手

  ///&LT;总结&gt;
    ///获取邀请令牌。
    ///&LT; /总结&gt;
    ///&LT; PARAM NAME =电子邮件&gt;将电子邮件和LT; /参数&GT;
    ///&LT;&回报GT;&LT; /回报&GT;
    公共静态字符串GetTokenForInvitation(字符串email)
    {
        如果(String.IsNullOrEmpty(电子邮件))
            抛出新的ArgumentException(电子邮件不能为空);        字符串标记= Password.En codeMessageWithPassword(的String.Format({0}#{1},电子邮件,DateTime.Now),SEED);        返回记号。
    }
    ///&LT;总结&gt;
    ///从令牌获取电子邮件。
    ///&LT; /总结&gt;
    ///&LT; PARAM NAME =令牌方式&gt;的令牌LT; /参数&GT;
    ///&LT; PARAM NAME =电子邮件&gt;将电子邮件和LT; /参数&GT;
    ///&LT;&回报GT;&LT; /回报&GT;
    公共静态布尔GetEmailFromToken(字符串标记,出字符串email)
    {
        电子邮件=的String.Empty;
        字符串消息= Password.De codeMessageWithPassword(令牌,SEED);
        字符串[] = messageParts message.Split('#');        如果(messageParts.Count()!= 2)
        {
            返回false;
            //没有正确生成的标记。
        }
        其他
        {
            电子邮件= messageParts [0];
            返回true;
        }
    }    ///&LT;总结&gt;
    用于生成令牌///助手功能注册的第一次,以确认他们的电子邮件地址时,向用户发送的消息中使用。
    ///&LT; /总结&gt;
    ///&LT; PARAM NAME =电子邮件方式&gt;的电子邮件地址EN code&LT; /参数&GT;
    ///&LT;收益方式&gt;从电子邮件地址,时间戳生成的令牌,种子值&LT; /回报&GT;
    公共静态字符串GetTokenForValidation(字符串email)
    {
        如果(String.IsNullOrEmpty(电子邮件))
            抛出新的ArgumentException(电子邮件不能为空);        字符串标记= Password.En codeMessageWithPassword(的String.Format({0}#{1},电子邮件,DateTime.Now),SEED);        返回记号。
    }
    ///&LT;总结&gt;
    ///验证给定的令牌是否有效的确定的电子邮件地址。
    ///&LT; /总结&gt;
    ///&LT; PARAM NAME =令牌方式&gt;令牌验证&LT; /参数&GT;
    ///&LT; PARAM NAME =电子邮件方式&gt;的电子邮件地址在验证使用&lt; /参数&GT;
    ///&LT;&回报GT;&LT; C&GT;真&LT; / c取代;如果令牌是有效的,&LT; c取代假LT; / c取代;否则&LT; /回报&GT;
    公共静态布尔IsTokenValid(字符串标记,字符串email)
    {
        返回IsTokenValid(令牌,电子邮件,DateTime.Now);
    }
    ///&LT;总结&gt;
    ///核心方法来验证令牌还提供了一个时间戳进行测试。在生产模式下应始终DateTime.Now。
    ///&LT; /总结&gt;
    ///&LT; PARAM NAME =令牌方式&gt;令牌验证&LT; /参数&GT;
    ///&LT; PARAM NAME =电子邮件方式&gt;的电子邮件地址在验证使用&lt; /参数&GT;
    ///&所述; PARAM NAME =时间戳&gt;将时间戳重新presenting其中执行验证时与所述; /参数&GT;
    ///&LT;&回报GT;&LT; C&GT;真&LT; / c取代;如果令牌是有效的,&LT; c取代假LT; / c取代;否则&LT; /回报&GT;
    公共静态布尔IsTokenValid(字符串标记,字符串email,日期戳)
    {
        如果(String.IsNullOrEmpty(标记))
            抛出新的ArgumentException(令牌不能为空);        尝试
        {
            字符串消息= Password.De codeMessageWithPassword(令牌,SEED);
            字符串[] = messageParts message.Split('#');            如果(messageParts.Count()!= 2)
            {
                返回false;
                //没有正确生成的标记。
            }
            其他
            {
                串messageEmail = messageParts [0];
                串messageDate = messageParts [1];                //如果电子邮件是相同的,并且其中所述令牌创建是超过5天不再的时间,那么它是有效的。否则,它不是。
                返回(的String.Compare(电子邮件,messageEmail,真)== 0&放大器;&放大器; timestamp.Subtract(DateTime.Parse(messageDate))天小于5);
            }
        }
        赶上(例外)
        {
            //不能解密消息。令牌已被篡改。
            返回false;
        }
    }

终于在这里的一些code加密,decript令牌...

我有它在密码,旨在成为一个辅助类。

///编辑:
删除了两个功能我之前引用,并显示完整的辅助类。

下面是与所有辅助功能的密码静态类。

 使用系统;
使用System.Text;
使用System.IO;
使用System.Security.Cryptography;
使用System.Data这;
使用在System.Resources;命名空间MySolution.Common.Util
{
    ///&LT;总结&gt;
    ///实现一些功能,支持密码操作或代
    ///&LT; /总结&gt;
    公共类密码
    {
        ///&LT;总结&gt;
        ///接受一个字符串,并产生16字节的哈希值。
        ///&LT; /总结&gt;
        ///&LT; PARAM NAME =STR&gt;该字符串被散列&LT; /参数&GT;
        ///&LT; PARAM NAME =了passwordFormat&GT;选择使用的哈希算法。可接受的值是SHA1和MD5&LT; /参数&GT;
        ///&LT;收益方式&gt;哈希密码的十六进制字符串&LT; /回报&GT;
        公共静态字符串连接codeString的(字符串str,串了passwordFormat)
        {
            如果(STR == NULL)
                返回null;            ASCIIEncoding AE =新ASCIIEncoding();
            字节[]的结果;
            开关(了passwordFormat)
            {
                案SHA1:
                    SHA1 SHA1 =新System.Security.Cryptography.SHA1CryptoServiceProvider();
                    结果= sha1.ComputeHash(AE.GetBytes(STR));
                    打破;
                案MD5:
                    MD5 MD5 =新System.Security.Cryptography.MD5CryptoServiceProvider();
                    结果= md5.ComputeHash(AE.GetBytes(STR));
                    打破;
                默认:
                    抛出新的ArgumentException(了passwordFormat无效的格式值接受的值是SHA1和MD5。);
            }            //循环散列数据的每个字节
            //并格式化每一个作为十六进制字符串。
            StringBuilder的SB =新的StringBuilder(16);
            的for(int i = 0; I&LT; result.Length;我++)
            {
                sb.Append(导致[I]的ToString(×2));
            }
            返回sb.ToString();
        }        ///&LT;总结&gt;
        ///接受一个字符串,并产生16字节的哈希值。默认情况下使用MD5。
        ///&LT; /总结&gt;
        ///&LT; PARAM NAME =STR&gt;该字符串被散列&LT; /参数&GT;
        ///&LT;收益方式&gt;哈希密码的十六进制字符串&LT; /回报&GT;
        公共静态字符串连接codeString的(字符串str)
        {
            返回恩codeString的(STR,MD5);
        }        ///&LT;总结&gt;
        ///接受一个字符串,并产生16字节的哈希值。
        ///&LT; /总结&gt;
        ///&LT; PARAM NAME =STR&gt;该字符串被散列&LT; /参数&GT;
        ///&LT; PARAM NAME =了passwordFormat&GT;选择使用的哈希算法。可接受的值是SHA1和MD5&LT; /参数&GT;
        ///&LT;收益方式&gt;哈希密码的字符串&LT; /回报&GT;
        公共静态字符串连接codeBinary(字节[]缓冲区,串了passwordFormat)
        {
            如果(缓冲== NULL)
                返回null;            字节[]的结果;
            开关(了passwordFormat)
            {
                案SHA1:
                    SHA1 SHA1 =新System.Security.Cryptography.SHA1CryptoServiceProvider();
                    结果= sha1.ComputeHash(缓冲液);
                    打破;
                案MD5:
                    MD5 MD5 =新System.Security.Cryptography.MD5CryptoServiceProvider();
                    结果= md5.ComputeHash(缓冲液);
                    打破;
                默认:
                    抛出新的ArgumentException(了passwordFormat无效的格式值接受的值是SHA1和MD5。);
            }
            //循环散列数据的每个字节
            //并格式化每一个作为十六进制字符串。
            StringBuilder的SB =新的StringBuilder(16);
            的for(int i = 0; I&LT; result.Length;我++)
            {
                sb.Append(导致[I]的ToString(×2));
            }
            返回sb.ToString();
        }        ///&LT;总结&gt;
        ///恩codeS使用默认的密码提供缓冲。
        ///&LT; /总结&gt;
        ///&所述; PARAM NAME =缓冲&gt;将缓冲器下; /参数&GT;
        ///&LT;&回报GT;&LT; /回报&GT;
        公共静态字符串连接codeBinary(字节[]缓冲区)
        {
            返回恩codeBinary(缓冲区,MD5);
        }        ///&LT;总结&gt;
        ///创建一个随机的字母数字密码。
        ///&LT; /总结&gt;
        ///&LT;收益方式&gt;默认的长字符串使用新密码&LT; /回报&GT;
        ///&LT;说明&gt;该密码的默认长度为8个字符&LT; /备注&GT;
        公共静态字符串CreateRandomPassword()
        {
            //默认长度为8个字符
            返回CreateRandomPassword(8);
        }        ///&LT;总结&gt;
        ///创建的尺寸(长度)的随机字母数字密码。
        ///&LT; /总结&gt;
        ///&所述; PARAM NAME =长度&gt;在密码&所述的字符数; /参数&GT;
        ///&LT;返回&gt;将生成的密码&LT; /回报&GT;
        公共静态字符串CreateRandomPassword(INT长度)
        {
            随机RND =新的随机(Convert.ToInt32(DateTime.Now.Millisecond)); //创建从时间的种子
            字符串密码=;
            而(Password.Length&LT;长度)
            {
                炭newChar = Convert.ToChar((int)的((122 - 48 + 1)* rnd.NextDouble()+ 48));
                如果((((int)的newChar)GT; =((int)的'A'))及(((int)的newChar)所述; =((int)的'Z'))|(((int)的newChar) &GT; =((int)的'A'))及(((int)的newChar)所述; =((int)的'Z'))|(((int)的newChar)GT; =((int)的'0 '))及(((int)的newChar)所述; =((int)的'9')))
                    密码+ = newChar;
            }
            返回密码;
        }        ///&LT;总结&gt;
        ///将一个文本消息并使用密码作为密钥加密。
        ///&LT; /总结&gt;
        ///&LT; PARAM NAME =plainMessage方式&gt;的文本加密&LT; /参数&GT;
        ///&LT; PARAM NAME =密码&gt;到加密与消息的密码&LT; /参数&GT;
        ///&LT;退货和GT;加密字符串&LT; /回报&GT;
        ///&LT;说明方式&gt;此方法使用了TripleDes symmmectric加密&LT; /言论&GT;
        公共静态字符串连接codeMessageWithPassword(字符串plainMessage,字符串密码)
        {
            如果(plainMessage == NULL)
                抛出新的ArgumentNullException(encryptedMessage,信息不能为空);            TripleDESCryptoServiceProvider DES =新TripleDESCryptoServiceProvider();
            des.IV =新的字节[8];            //创建基于字节数组的密码,并将其存储的关键。
            PasswordDeriveBytes PDB =新PasswordDeriveBytes(密码,新的字节[0]);
            des.Key = pdb.CryptDeriveKey(RC2,MD5,128,新的字节[8]);            MemoryStream的毫秒=新的MemoryStream(plainMessage.Length * 2);
            CryptoStream的encStream =新的CryptoStream(MS,des.CreateEncryptor(),CryptoStreamMode.Write);
            字节[] = plainBytes Encoding.UTF8.GetBytes(plainMessage);
            encStream.Write(plainBytes,0,plainBytes.Length);
            encStream.FlushFinalBlock();
            字节[] = encryptedBytes新的字节[ms.Length]
            ms.Position = 0;
            ms.Read(encryptedBytes,0,(int)的ms.Length);
            encStream.Close();            返回Convert.ToBase64String(encryptedBytes);
        }        ///&LT;总结&gt;
        ///使用TripleDES的和密码作为密钥注意到加密消息,并将其转换为原始文本消息。
        ///&LT; /总结&gt;
        ///&LT; PARAM NAME =encryptedMessage方式&gt;加密的消息脱code&LT; /参数&GT;
        ///&LT; PARAM NAME =密码方式&gt;脱code消息的密码&LT; /参数&GT;
        ///&所述;返回&gt;将解密的消息与所述; /回报&GT;
        ///&LT;说明方式&gt;此方法使用了TripleDes symmmectric加密&LT; /言论&GT;
        公共静态字符串德codeMessageWithPassword(字符串encryptedMessage,字符串密码)
        {
            如果(encryptedMessage == NULL)
                抛出新的ArgumentNullException(encryptedMessage,加密的消息不能为空);            TripleDESCryptoServiceProvider DES =新TripleDESCryptoServiceProvider();
            des.IV =新的字节[8];            //创建基于字节数组的密码,并将其存储的关键。
            PasswordDeriveBytes PDB =新PasswordDeriveBytes(密码,新的字节[0]);
            des.Key = pdb.CryptDeriveKey(RC2,MD5,128,新的字节[8]);            //此行保护+迹象表明,得到用空格代替,当发送时该参数不urlen codeD。
            encryptedMessage = encryptedMessage.Replace(,+);
            MemoryStream的毫秒=新的MemoryStream(encryptedMessage.Length * 2);
            CryptoStream的decStream =新的CryptoStream(MS,des.CreateDecryptor(),CryptoStreamMode.Write);            字节[] plainBytes;
            尝试
            {
                字节[] = encBytes Convert.FromBase64String(Convert.ToString(encryptedMessage));
                decStream.Write(encBytes,0,encBytes.Length);
                decStream.FlushFinalBlock();
                plainBytes =新的字节[ms.Length]
                ms.Position = 0;
                ms.Read(plainBytes,0,(int)的ms.Length);
                decStream.Close();
            }
            赶上(CryptographicException E)
            {
                抛出新ApplicationException的(,E无法解密的消息可能,密码是错误的。);
            }            返回Encoding.UTF8.GetString(plainBytes);
        }
    }
}

How to implement password reset in MVC2 application?

Passwords are hashed using ASP .NET membership provider. Password recovery question is not used. Standard ASP .NET MVC2 project template with standard AccountController class is used.

If user forgots password, email with temporary link or with new password should sent to user e-mail address .

Where to find code to implement this in MVC 2 C# ?

stack overflow contains two answers which discuss methods about implementing this. There is not sample code. I googled for "asp .net mvc password reset c# sample code download" but havent found sample code for this.

I'm new to MVC. Where to find sample code for password recovery? This is missing from VS2010 generated project template.

Update

I tried this code in Mono 2.10 but got exception:

CspParameters not supported by Mono

at line

        des.Key = pdb.CryptDeriveKey("RC2", "MD5", 128, new byte[8]);

How to run it in Mono ?

Stack Trace:

System.NotSupportedException: CspParameters not supported by Mono
at System.Security.Cryptography.PasswordDeriveBytes.CryptDeriveKey (string,string,int,byte[]) [0x0001b] in /usr/src/redhat/BUILD/mono-2.10.2/mcs/class/corlib/System.Security.Cryptography/PasswordDeriveBytes.cs:197
at store2.Helpers.Password.EncodeMessageWithPassword (string,string) <IL 0x00055, 0x000f3>
at store2.Helpers.AccountHelper.GetTokenForValidation (string) <IL 0x00033, 0x00089>
at MvcMusicStore.Controllers.AccountController.PasswordReminder (MvcMusicStore.Models.PasswordReminderModel) <IL 0x001ac, 0x00495>
at (wrapper dynamic-method) System.Runtime.CompilerServices.ExecutionScope.lambda_method (System.Runtime.CompilerServices.ExecutionScope,System.Web.Mvc.ControllerBase,object[]) <IL 0x00020, 0x0005b>
at System.Web.Mvc.ActionMethodDispatcher.Execute (System.Web.Mvc.ControllerBase,object[]) <IL 0x00008, 0x0001b>
at System.Web.Mvc.ReflectedActionDescriptor.Execute (System.Web.Mvc.ControllerContext,System.Collections.Generic.IDictionary`2<string, object>) <IL 0x00072, 0x00103>
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod (System.Web.Mvc.ControllerContext,System.Web.Mvc.ActionDescriptor,System.Collections.Generic.IDictionary`2<string, object>) <IL 0x00003, 0x00019>
at System.Web.Mvc.ControllerActionInvoker/<>c__DisplayClassd.<InvokeActionMethodWithFilters>b__a () <IL 0x0002d, 0x00068>
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter (System.Web.Mvc.IActionFilter,System.Web.Mvc.ActionExecutingContext,System.Func`1<System.Web.Mvc.ActionExecutedContext>) <IL 0x00031, 0x000b6>


--------------------------------------------------------------------------------
Version information: Mono Runtime Version: 2.10.2 (tarball Mon Apr 18 18:57:39 UTC 2011); ASP.NET Version: 2.0.50727.1433

解决方案

Here is my approach. In MVC you will have an action called RetrievePassword where you will ask for the user's email address and pass it in a post

    [HttpGet]
    public ActionResult RetrievePassword()
    {
        return View();
    }

    [HttpPost]
    public ActionResult RetrievePassword(PasswordRetrievalModel model)
    {
        if (ModelState.IsValid)
        {
            string username = Membership.GetUserNameByEmail(model.Email);

            if (!String.IsNullOrEmpty(username))
            {
                // This is a helper function that sends an email with a token (an MD5).
                NotificationsHelper.SendPasswordRetrieval(model.Email, this.ControllerContext);
            }
            else
            {
                Trace.WriteLine(String.Format("*** WARNING:  A user tried to retrieve their password but the email address used '{0}' does not exist in the database.", model.Email));
             }


            return RedirectToAction("Index", "Home");
        }

        return View(model);
    }

An email message will be sent with a url that redirects to http://example.com/Account/Validate?email=xxxxxxxx&token=xxxxxxxx

If the token is valid for the email, you will probably display a password reset form so they choose a new password.

So you need a Validate Action:

[HttpGet]
    [CompressFilter]
    public ActionResult Validate(string email, string token)
    {
        bool isValid = false;

        if (AccountHelper.IsTokenValid(token, email))
        {
            string username = Membership.GetUserNameByEmail(email);
            if (!String.IsNullOrEmpty(username))
            {
                // Get the user and approve it.
                MembershipUser user = Membership.GetUser(username);
                user.IsApproved = true;
                Membership.UpdateUser(user);

                isValid = true;

                // Since it was a successful validation, authenticate the user.
                FormsAuthentication.SetAuthCookie(username, false);
            }
            else
            {
                isValid = false;
            }
        }

        return View(isValid);
    }

Here are some of the helpers you see in this code:

Account Helper

/// <summary>
    /// Gets the token for invitation.
    /// </summary>
    /// <param name="email">The email.</param>
    /// <returns></returns>
    public static string GetTokenForInvitation(string email)
    {
        if (String.IsNullOrEmpty(email))
            throw new ArgumentException("The email cannot be null");

        string token = Password.EncodeMessageWithPassword(String.Format("{0}#{1}", email, DateTime.Now), SEED);

        return token;
    }


    /// <summary>
    /// Gets the email from token.
    /// </summary>
    /// <param name="token">The token.</param>
    /// <param name="email">The email.</param>
    /// <returns></returns>
    public static bool GetEmailFromToken(string token, out string email)
    {
        email = String.Empty;


        string message = Password.DecodeMessageWithPassword(token, SEED);
        string[] messageParts = message.Split('#');

        if (messageParts.Count() != 2)
        {
            return false;
            // the token was not generated correctly.
        }
        else
        {
            email = messageParts[0];
            return true;
        }
    }



    /// <summary>
    /// Helper function used to generate a token to be used in the message sent to users when registered the first time to confirm their email address.
    /// </summary>
    /// <param name="email">The email address to encode.</param>
    /// <returns>The token generated from the email address, timestamp, and SEED value.</returns>
    public static string GetTokenForValidation(string email)
    {
        if (String.IsNullOrEmpty(email))
            throw new ArgumentException("The email cannot be null");

        string token = Password.EncodeMessageWithPassword(String.Format("{0}#{1}", email, DateTime.Now), SEED);

        return token;
    }


    /// <summary>
    /// Validates whether a given token is valid for a determined email address.
    /// </summary>
    /// <param name="token">The token to validate.</param>
    /// <param name="email">The email address to use in the validation.</param>
    /// <returns><c>true</c> if the token is valid, <c>false</c> otherwise.</returns>
    public static bool IsTokenValid(string token, string email)
    {
        return IsTokenValid(token, email, DateTime.Now);
    }


    /// <summary>
    /// Core method to validate a token that also offers a timestamp for testing.  In production mode should always be DateTime.Now.
    /// </summary>
    /// <param name="token">The token to validate.</param>
    /// <param name="email">the email address to use in the validation.</param>
    /// <param name="timestamp">The timestamp representing the time in which the validation is performed.</param>
    /// <returns><c>true</c> if the token is valid, <c>false</c> otherwise.</returns>
    public static bool IsTokenValid(string token, string email, DateTime timestamp)
    {
        if (String.IsNullOrEmpty(token))
            throw new ArgumentException("The token cannot be null");

        try
        {
            string message = Password.DecodeMessageWithPassword(token, SEED);
            string[] messageParts = message.Split('#');

            if (messageParts.Count() != 2)
            {
                return false;
                // the token was not generated correctly.
            }
            else
            {
                string messageEmail = messageParts[0];
                string messageDate = messageParts[1];

                // If the emails are the same and the date in which the token was created is no longer than 5 days, then it is valid. Otherwise, it is not. 
                return (String.Compare(email, messageEmail, true) == 0 && timestamp.Subtract(DateTime.Parse(messageDate)).Days < 5);
            }
        }
        catch (Exception)
        {
            // could not decrypt the message. The token has been tampered with.
            return false;
        }
    }

And Finally here some code to encrypt, decript a token...

I have it in a Password class that is intended to be a helper.

/// EDIT: Removed the two functions I referenced before and show the full helper class.

Here is the Password static class with all helper functions.

using System;
using System.Text;
using System.IO;
using System.Security.Cryptography;
using System.Data;
using System.Resources;

namespace MySolution.Common.Util
{
    /// <summary>
    /// Implements some functions to support password manipulation or generation
    /// </summary>
    public class Password
    {
        /// <summary>
        /// Takes a string and generates a hash value of 16 bytes.
        /// </summary>
        /// <param name="str">The string to be hashed</param>
        /// <param name="passwordFormat">Selects the hashing algorithm used. Accepted values are "sha1" and "md5".</param>
        /// <returns>A hex string of the hashed password.</returns>
        public static string EncodeString(string str, string passwordFormat)
        {
            if (str == null)
                return null;

            ASCIIEncoding AE = new ASCIIEncoding();
            byte[] result;
            switch (passwordFormat)
            {
                case "sha1":                    
                    SHA1 sha1 = new System.Security.Cryptography.SHA1CryptoServiceProvider();
                    result = sha1.ComputeHash(AE.GetBytes(str));
                    break;
                case "md5":
                    MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
                    result = md5.ComputeHash(AE.GetBytes(str));
                    break;
                default:
                    throw new ArgumentException("Invalid format value. Accepted values are 'sha1' and 'md5'.", "passwordFormat");
            }

            // Loop through each byte of the hashed data 
            // and format each one as a hexadecimal string.
            StringBuilder sb = new StringBuilder(16);
            for (int i = 0; i < result.Length; i++)
            {
                sb.Append(result[i].ToString("x2"));
            }


            return sb.ToString();
        }

        /// <summary>
        /// Takes a string and generates a hash value of 16 bytes.  Uses "md5" by default.
        /// </summary>
        /// <param name="str">The string to be hashed</param>
        /// <returns>A hex string of the hashed password.</returns>
        public static string EncodeString(string str)
        {
            return EncodeString(str, "md5");
        }



        /// <summary>
        /// Takes a string and generates a hash value of 16 bytes.
        /// </summary>
        /// <param name="str">The string to be hashed</param>
        /// <param name="passwordFormat">Selects the hashing algorithm used. Accepted values are "sha1" and "md5".</param>
        /// <returns>A string of the hashed password.</returns>
        public static string EncodeBinary(byte[] buffer, string passwordFormat)
        {
            if (buffer == null)
                return null;

            byte[] result;
            switch (passwordFormat)
            {
                case "sha1":
                    SHA1 sha1 = new System.Security.Cryptography.SHA1CryptoServiceProvider();
                    result = sha1.ComputeHash(buffer);
                    break;
                case "md5":
                    MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
                    result = md5.ComputeHash(buffer);
                    break;
                default:
                    throw new ArgumentException("Invalid format value. Accepted values are 'sha1' and 'md5'.", "passwordFormat");
            }


            // Loop through each byte of the hashed data 
            // and format each one as a hexadecimal string.
            StringBuilder sb = new StringBuilder(16);
            for (int i = 0; i < result.Length; i++)
            {
                sb.Append(result[i].ToString("x2"));
            }


            return sb.ToString();
        }

        /// <summary>
        /// Encodes the buffer using the default cryptographic provider.
        /// </summary>
        /// <param name="buffer">The buffer.</param>
        /// <returns></returns>
        public static string EncodeBinary(byte[] buffer)
        {
            return EncodeBinary(buffer, "md5");
        }





        /// <summary>
        /// Creates a random alphanumeric password.
        /// </summary>
        /// <returns>A default length character string with the new password.</returns>
        /// <remarks>The default length of the password is eight (8) characters.</remarks>
        public static string CreateRandomPassword()
        {
            //Default length is 8 characters
            return CreateRandomPassword(8);
        }

        /// <summary>
        /// Creates a random alphanumeric password on dimension (Length).
        /// </summary>
        /// <param name="Length">The number of characters in the password</param>
        /// <returns>The generated password</returns>
        public static string CreateRandomPassword(int Length)
        {
            Random rnd = new Random(Convert.ToInt32(DateTime.Now.Millisecond));  //Creates the seed from the time
            string Password="";
            while (Password.Length < Length ) 
            {
                char newChar = Convert.ToChar((int)((122 - 48 + 1) * rnd.NextDouble() + 48));
                if ((((int) newChar) >= ((int) 'A')) & (((int) newChar) <= ((int) 'Z')) | (((int) newChar) >= ((int) 'a')) & (((int) newChar) <= ((int) 'z')) | (((int) newChar) >= ((int) '0')) & (((int) newChar) <= ((int) '9')))
                    Password += newChar;
            }
            return Password;
        }

        /// <summary>
        /// Takes a text message and encrypts it using a password as a key.
        /// </summary>
        /// <param name="plainMessage">A text to encrypt.</param>
        /// <param name="password">The password to encrypt the message with.</param>
        /// <returns>Encrypted string.</returns>
        /// <remarks>This method uses TripleDES symmmectric encryption.</remarks>
        public static string EncodeMessageWithPassword(string plainMessage, string password)
        {
            if (plainMessage == null)
                throw new ArgumentNullException("encryptedMessage", "The message cannot be null");

            TripleDESCryptoServiceProvider des = new TripleDESCryptoServiceProvider();
            des.IV = new byte[8];

            //Creates the key based on the password and stores it in a byte array.
            PasswordDeriveBytes pdb = new PasswordDeriveBytes(password, new byte[0]);
            des.Key = pdb.CryptDeriveKey("RC2", "MD5", 128, new byte[8]);

            MemoryStream ms = new MemoryStream(plainMessage.Length * 2);
            CryptoStream encStream = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write);
            byte[] plainBytes = Encoding.UTF8.GetBytes(plainMessage);
            encStream.Write(plainBytes, 0, plainBytes.Length);
            encStream.FlushFinalBlock();
            byte[] encryptedBytes = new byte[ms.Length];
            ms.Position = 0;
            ms.Read(encryptedBytes, 0, (int)ms.Length);
            encStream.Close();

            return Convert.ToBase64String(encryptedBytes);
        }

        /// <summary>
        /// Takes an encrypted message using TripleDES and a password as a key and converts it to the original text message.
        /// </summary>
        /// <param name="encryptedMessage">The encrypted message to decode.</param>
        /// <param name="password">The password to decode the message.</param>
        /// <returns>The Decrypted message</returns>
        /// <remarks>This method uses TripleDES symmmectric encryption.</remarks>
        public static string DecodeMessageWithPassword(string encryptedMessage, string password)
        {
            if (encryptedMessage == null)
                throw new ArgumentNullException("encryptedMessage", "The encrypted message cannot be null");

            TripleDESCryptoServiceProvider des = new TripleDESCryptoServiceProvider();
            des.IV = new byte[8];

            //Creates the key based on the password and stores it in a byte array.
            PasswordDeriveBytes pdb = new PasswordDeriveBytes(password, new byte[0]);
            des.Key = pdb.CryptDeriveKey("RC2", "MD5", 128, new byte[8]);

            //This line protects the + signs that get replaced by spaces when the parameter is not urlencoded when sent.
            encryptedMessage = encryptedMessage.Replace(" ", "+");
            MemoryStream ms = new MemoryStream(encryptedMessage.Length * 2);
            CryptoStream decStream = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write);

            byte[] plainBytes; 
            try 
            {
                byte[] encBytes = Convert.FromBase64String(Convert.ToString(encryptedMessage));
                decStream.Write(encBytes, 0, encBytes.Length);
                decStream.FlushFinalBlock();                
                plainBytes = new byte[ms.Length];
                ms.Position = 0;                
                ms.Read(plainBytes, 0, (int)ms.Length);
                decStream.Close();
            }
            catch(CryptographicException e)
            {
                throw new ApplicationException("Cannot decrypt message.  Possibly, the password is wrong", e);
            }

            return Encoding.UTF8.GetString(plainBytes);
        }
    }
}

这篇关于在哪里可以找到C#示例code来实现ASP .NET MVC2密码恢复的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆