AspNetCore-MVC實戰系列(二)之通過綁定郵箱找回密碼

来源:http://www.cnblogs.com/wangrudong003/archive/2017/04/28/6780637.html
-Advertisement-
Play Games

AspNetCore - MVC實戰系列目錄 . 愛留圖網站誕生 . AspNetCore - MVC實戰系列(一)之Sqlserver表映射實體模型 . AspNetCore-MVC實戰系列(二)之通過綁定郵箱找回密碼 開篇嘮嗑 本篇內容寫在5.1假期前夕,主要是讓大家能在節假日休息充點的時候能有 ...


AspNetCore - MVC實戰系列目錄

. 愛留圖網站誕生

. AspNetCore - MVC實戰系列(一)之Sqlserver表映射實體模型

AspNetCore-MVC實戰系列(二)之通過綁定郵箱找回密碼

開篇嘮嗑

本篇內容寫在5.1假期前夕,主要是讓大家能在節假日休息充點的時候能有好的乾貨例子,到目前為止netcore方面的實戰例子分享即將進入正軌,謝謝各位朋友多多支持;最近工作安排的新項目即將開始,項目前期就我一人搭建,讓我猶豫的是對於公司這個內部系統並且是初建的項目用什麼開發方式好呢,最初考慮的是mvc5但是又想了下如果這樣還不如直接使用NetCore1.1的MVC呢,因為現在這版本基本也算穩定了可以試試水,可是又有顧慮是mvc項目在上線的時候會影響到其他人的使用(前期不考慮nginx分發),然後目光又轉向aspx網站的方式,不得不說這種方式在發佈上的確有優勢,尤其是在沒有分散式的前提下;好吧目前還在考慮中,希望能得到各位朋友的建議。。。

註冊模塊

首先,這裡講解的內容對應的實體和表結構是基於上一篇文章創建的項目這裡就不多說了;對於一個註冊功能來說,通常需要的屬性是:賬號,密碼,確認密碼,驗證碼(可省略),甚至有些快捷的註冊方式就是通過手機號來註冊,當然咋們沒有簡訊通道的功能不能發簡訊,所以採用前者,先來看下Action中設計代碼:

Register的get路由Action

1  // GET: Member/Create
2         public IActionResult Register()
3         {
4             return View();
5         }

Register的post提交註冊信息的Action

 1 [HttpPost]
 2         [ValidateAntiForgeryToken]
 3         public async Task<IActionResult> Register([Bind("UserName,UserPwd,ComfirmPwd")] MoRegisterUser loginUser)
 4         {
 5             if (ModelState.IsValid)
 6             {
 7                 #region 驗證
 8                 if (_context.ToUserInfo.Any(b => b.UserName.ToUpper() == loginUser.UserName.Trim().ToUpper()))
 9                 {
10                     this.MsgBox("已經存在相同的賬號!");
11                     return View(loginUser);
12                 }
13                 #endregion
14 
15                 #region 入庫
16 
17                 ToUserInfo userInfo = new ToUserInfo();
18 
19                 userInfo.UserName = loginUser.UserName.Trim();
20                 userInfo.UserPwd = PublicClass._Md5(loginUser.UserPwd.Trim());
21                 userInfo.NickName = userInfo.UserName;
22                 userInfo.Status = (int)EnumHelper.EmUserStatus.啟用;
23                 userInfo.CreateTime = DateTime.Now;
24                 userInfo.LevelNum = (int)EmLevelNum.註冊;
25 
26                 userInfo.Ips = this.GetUserIp();
27                 userInfo.HeadPhoto = "/images/ailiutu_user.png";
28                 userInfo.Sex = false;
29 
30                 _context.Add(userInfo);
31                 var result = await _context.SaveChangesAsync();
32                 if (result > 0)
33                 {
34                     var moUserInfo = new MoUserInfo
35                     {
36                         Id = userInfo.Id,
37                         UserName = userInfo.UserName,
38                         NickName = userInfo.NickName,
39                         Addr = userInfo.Addr,
40                         Birthday = userInfo.Birthday,
41 
42                         Blog = userInfo.Blog,
43                         CreateTime = userInfo.CreateTime,
44                         Email = userInfo.Email,
45                         HeadPhoto = userInfo.HeadPhoto,
46                         Introduce = userInfo.Introduce,
47 
48                         Ips = userInfo.Ips,
49                         LevelNum = userInfo.LevelNum,
50                         Sex = userInfo.Sex,
51                         Tel = userInfo.Tel,
52                         Status = userInfo.Status,
53 
54                         LoginTime = DateTime.Now
55                     };
56                     HttpContext.Session.Set<MoUserInfo>(HttpContext.Session.SessionKey(), moUserInfo);
57 
58                     if (!string.IsNullOrWhiteSpace(moUserInfo.Ips))
59                     {
60                         _context.ToUserLog.Add(new ToUserLog
61                         {
62                             CodeId = (int)EmLogCode.登錄,
63                             CreateTime = DateTime.Now,
64                             Des = $"IP:{moUserInfo.Ips},登錄時間:{moUserInfo.LoginTime.ToString("yyyy-MM-dd HH:mm")}",
65                             UserId = userInfo.Id
66                         });
67                     }
68 
69                     _context.ToUserLog.Add(new ToUserLog
70                     {
71                         CodeId = (int)EmLogCode.積分,
72                         CreateTime = DateTime.Now,
73                         Des = $"【註冊】  +{(int)EmLevelNum.註冊}",
74                         UserId = userInfo.Id
75                     });
76                     await _context.SaveChangesAsync();
77 
78                     return RedirectToAction(nameof(HomeController.Index), "home");
79                 }
80                 #endregion
81 
82                 this.MsgBox("註冊失敗,請稍後重試。");
83                 return View(loginUser);
84             }
85             return View(loginUser);
86         }

通過Post的Action能夠看出註冊處理的Action主要操作步驟有以下幾點:

. ModelState.IsValid驗證提交的信息是否滿足model規則設置

. Linq的Any()方法驗證是否存在相同賬號

. _context.Add()入庫註冊信息

. HttpContext.Session.Set的擴展方法設置登陸的session

. 記錄登陸記錄和登陸增加的積分信息

對於一個簡單的註冊基本就是這樣的流程,我們來看看提交註冊時的模型實體:

 1  /// <summary>
 2     /// 註冊實體
 3     /// </summary>
 4     public class MoRegisterUser
 5     {
 6         [Required(AllowEmptyStrings = false, ErrorMessage = "賬號長度範圍6-30字元!")]
 7         [Display(Prompt = "郵箱/手機號/6-30字元")]
 8         [RegularExpression(@"[^\s]{6,30}", ErrorMessage = "賬號長度範圍6-30字元。")]
 9         public string UserName { get; set; }
10 
11         [Required(AllowEmptyStrings = false, ErrorMessage = "密碼長度範圍6-20字元!")]
12         [DataType(DataType.Password)]
13         [Display(Prompt = "密碼長度範圍6-20字元!")]
14         [RegularExpression(@"[^\s]{6,20}", ErrorMessage = "密碼長度範圍6-20字元。")]
15         public string UserPwd { get; set; }
16 
17         [Compare("UserPwd", ErrorMessage = "密碼與確認密碼不相同!")]
18         [DataType(DataType.Password)]
19         [Display(Prompt = "必須與密碼相同")]
20         public string ComfirmPwd { get; set; }
21     }

這裡自定義的註冊模型,設置了DataAnnotations,以此來快速設置驗證,不用再每個都用js寫了,mvc框架幫你做了這些;下麵看看View的代碼:

 1 @model LovePicture.Model.MoClass.MoRegisterUser
 2 
 3 @{
 4     ViewData["Title"] = "註冊";
 5 }
 6 
 7 <h3><span class="glyphicon glyphicon-flag" aria-hidden="true"></span> 註冊</h3>
 8 <form name="form_submit" asp-action="Register">
 9     <div class="form-horizontal">
10         <h4>  愛留圖:歡迎您成為我們的一份子,讓我們一起留存珍惜的圖片吧。</h4>
11         <hr />
12         <div asp-validation-summary="ModelOnly" class="text-danger"></div>
13         <div class="form-group">
14             <label asp-for="UserName" class="col-md-2 control-label">賬號</label>
15             <div class="col-md-10">
16                 <input asp-for="UserName" required="required" class="form-control" />
17                 <span asp-validation-for="UserName" class="text-danger"></span>
18             </div>
19         </div>
20         <div class="form-group">
21             <label asp-for="UserPwd" class="col-md-2 control-label">密碼</label>
22             <div class="col-md-10">
23                 <input asp-for="UserPwd" required="required" class="form-control" />
24                 <span asp-validation-for="UserPwd" class="text-danger"></span>
25             </div>
26         </div>
27         <div class="form-group">
28             <label asp-for="ComfirmPwd" class="col-md-2 control-label">確認密碼</label>
29             <div class="col-md-10">
30                 <input asp-for="ComfirmPwd" class="form-control" />
31                 <span asp-validation-for="ComfirmPwd" class="text-danger"></span>
32             </div>
33         </div>
34 
35         <div class="form-group">
36             <div class="col-md-offset-2 col-md-10">
37                 <input type="button" value="註 冊" name="btnSubmit" class="btn btn-default" />
38                 <span id="msgbox" style="color:red">@ViewData["msgbox"]</span>
39             </div>
40         </div>
41     </div>
42 </form>
43 <br />
44 <div>
45      <a href="/member/login">有賬號去登錄</a> | <a href="/member/ForgetPassword">忘記密碼?</a>
46 </div>
47 <script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
48 <script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>
View Code

對於mvc模型註解的方式在前端需要引入這兩個js文件

<script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>

View內容註意點在於我試圖中的Button按鈕是不是submit形式,這樣做的理由是,當您註冊的Action業務過多時,用戶點擊註冊按鈕提交數據,這個時候如果無法快速響應信息給用戶,那麼用戶可能多次點擊,因此就有個需求是需要吧註冊提交按鈕置灰或者影藏點,這裡我為了方便把全站點的提交按鈕都弄成統一name的按鈕了,最後用js來提交submit(註冊效果):

 1  bindSubmitBtn: function () {
 2             $("input[name='btnSubmit']").on("click", function () {
 3 
 4                 var _btn = $(this);
 5                 _btn.addClass("hide");
 6                 var _msg = $("#msgbox");
 7                 _msg.html("提交中,請稍後...");
 8 
 9                 var _form = $("form[name='form_submit']");
10                 if (_form.valid()) {
11                     _form.submit();
12                 } else {
13                     _btn.removeClass("hide");
14                     _msg.html("");
15                 }
16             });
17         }

登錄模塊

從代碼上來說登錄和註冊相差不大,功能上登錄模塊主要用來驗證登陸用戶是否存在,分配唯一sessionid,如果有跳轉地址還需要在登陸成功後執行跳回原訪問地址;

Login的Get方式Action

 1  // GET: Member
 2         public IActionResult Login(string returnUrl = null)
 3         {
 4             //獲取session
 5             var userInfo = HttpContext.Session.Get<MoUserInfo>(HttpContext.Session.SessionKey());
 6             if (userInfo != null)
 7             {
 8                 if (string.IsNullOrWhiteSpace(returnUrl)) { return RedirectToAction(nameof(HomeController.Index), "Home"); }
 9                 else { Redirect(returnUrl); }
10             }
11             this.MsgBox(returnUrl, "returnUrl");
12             return View();
13         }

Login的Post登錄方式Action

 1 [HttpPost]
 2         [ValidateAntiForgeryToken]
 3         public async Task<IActionResult> Login([Bind("UserName,UserPwd,ReturnUrl")] MoLoginUser loginUser)
 4         {
 5             if (ModelState.IsValid)
 6             {
 7                 #region 驗證
 8                 var md5Pwd = PublicClass._Md5(loginUser.UserPwd.Trim());
 9                 var userInfo = await _context.ToUserInfo.SingleOrDefaultAsync(b =>
10                         b.UserName.Equals(loginUser.UserName, StringComparison.CurrentCultureIgnoreCase) &&
11                         b.UserPwd.Equals(md5Pwd));
12                 if (userInfo == null)
13                 {
14                     this.MsgBox("賬號或密碼錯誤!");
15                     return View(loginUser);
16                 }
17                 else if (userInfo.Status == (int)EnumHelper.EmUserStatus.禁用)
18                 {
19                     this.MsgBox("該賬號已被禁用,或許你可以嘗試重新註冊一個賬號!");
20                     return View(loginUser);
21                 }
22                 #endregion
23 
24                 #region 更新登錄信息
25                 userInfo.Ips = this.GetUserIp();
26                 userInfo.LoginTime = DateTime.Now;
27                 userInfo.LevelNum += (int)EmLevelNum.登錄;
28 
29                 //記錄session
30                 var moUserInfo = new MoUserInfo
31                 {
32                     Id = userInfo.Id,
33                     UserName = userInfo.UserName,
34                     NickName = userInfo.NickName,
35                     Addr = userInfo.Addr,
36                     Birthday = userInfo.Birthday,
37 
38                     Blog = userInfo.Blog,
39                     CreateTime = userInfo.CreateTime,
40                     Email = userInfo.Email,
41                     HeadPhoto = userInfo.HeadPhoto,
42                     Introduce = userInfo.Introduce,
43 
44                     Ips = userInfo.Ips,
45                     LevelNum = userInfo.LevelNum,
46                     Sex = userInfo.Sex,
47                     Tel = userInfo.Tel,
48                     Status = userInfo.Status,
49 
50                     LoginTime = Convert.ToDateTime(userInfo.LoginTime)
51                 };
52                 HttpContext.Session.Set<MoUserInfo>(HttpContext.Session.SessionKey(), moUserInfo);
53 
54                 if (!string.IsNullOrWhiteSpace(moUserInfo.Ips))
55                 {
56                     _context.ToUserLog.Add(new ToUserLog
57                     {
58                         CodeId = (int)EmLogCode.登錄,
59                         CreateTime = DateTime.Now,
60                         Des = $"IP:{moUserInfo.Ips},登錄時間:{moUserInfo.LoginTime.ToString("yyyy-MM-dd HH:mm")}",
61                         UserId = userInfo.Id
62                     });
63                 }
64 
65                 _context.ToUserLog.Add(new ToUserLog
66                 {
67                     CodeId = (int)EmLogCode.積分,
68                     CreateTime = DateTime.Now,
69                     Des = $"【登錄】  +{(int)EmLevelNum.登錄}",
70                     UserId = userInfo.Id
71                 });
72 
73                 await _context.SaveChangesAsync();
74 
75                 if (string.IsNullOrWhiteSpace(loginUser.ReturnUrl)) { return RedirectToAction(nameof(HomeController.Index), "Home"); }
76                 else { return Redirect(loginUser.ReturnUrl); }
77                 #endregion
78             }
79             return View(loginUser);
80         }

這裡模仿微軟官方實例給出的樣子,把登陸和註冊實體模型分開了,因為登陸模型不需要什麼重覆密碼,並且還有其他的屬性如:回調地址,驗證碼等:

 1 /// <summary>
 2     /// 登錄實體
 3     /// </summary>
 4     public class MoLoginUser
 5     {
 6         [Required(AllowEmptyStrings = false, ErrorMessage = "賬號長度範圍6-30字元!")]
 7         [Display(Prompt = "郵箱/手機號/6-30字元")]
 8         [RegularExpression(@"[^\s]{6,30}", ErrorMessage = "賬號長度範圍6-30字元。")]
 9         public string UserName { get; set; }
10 
11         [Required(AllowEmptyStrings = false, ErrorMessage = "密碼長度範圍6-20字元!")]
12         [DataType(DataType.Password)]
13         [Display(Prompt = "密碼長度範圍6-20字元!")]
14         [RegularExpression(@"[^\s]{6,20}", ErrorMessage = "密碼長度範圍6-20字元。")]
15         public string UserPwd { get; set; }
16 
17         /// <summary>
18         /// 回跳地址
19         /// </summary>
20         public string ReturnUrl { get; set; }
21     }

同理對於登錄的view設計也和註冊差不多,只是不同網站對於安全設置可能會增加一些驗證碼,或其他的驗證方式而已,如下登錄View代碼:

 1 @model LovePicture.Model.MoClass.MoLoginUser
 2 
 3 @{
 4     ViewData["Title"] = "登錄";
 5 }
 6 
 7 <h3><span class="glyphicon glyphicon-send" aria-hidden="true"></span> 登錄</h3>
 8 <form name="form_submit" asp-action="Login">
 9     <div class="form-horizontal">
10         <h4>愛留圖:即刻登錄,讓我們一起留存珍惜的圖片吧。</h4>
11         <hr />
12         <div asp-validation-summary="ModelOnly" class="text-danger"></div>
13         <div class="form-group">
14             <label asp-for="UserName" class="col-md-2 control-label">賬號</label>
15             <div class="col-md-10">
16                 <input asp-for="UserName" required="required" class="form-control" />
17                 <span asp-validation-for="UserName" class="text-danger"></span>
18             </div>
19         </div>
20         <div class="form-group">
21             <label asp-for="UserPwd" class="col-md-2 control-label">密碼</label>
22             <div class="col-md-10">
23                 <input asp-for="UserPwd" required="required" class="form-control" />
24                 <span asp-validation-for="UserPwd" class="text-danger"></span>
25             </div>
26         </div>
27 
28         <div class="form-group">
29             <div class="col-md-offset-2 col-md-10">
30                 <input type="button" value="登 錄" name="btnSubmit" class="btn btn-default" /> <a href="/member/register" title="沒賬號來這裡註冊吧">沒賬號這裡註冊</a>
31                 <span id="msgbox" style="color:red">@ViewData["msgbox"]</span>
32             </div>
33         </div>
34     </div>
35     <input type="hidden" name="ReturnUrl" value="@ViewData["returnUrl"]" />
36 </form>
37 <br />
38 <div>
39     <a href="/member/register">沒賬號這裡註冊</a> | <a href="/member/ForgetPassword">忘記密碼?</a>
40 </div>
41 <script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
42 <script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>
View Code

郵箱找回密碼

來到這裡才真正進入今天的主題,對於一些有安全設置的網站來說通常有類似於通過綁定郵箱找回密碼的功能,這裡愛留圖目前也做了這樣的設置:

如果是綁

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 為什麼要使用StringBuilder 為什麼要使用StringBuilder 為什麼要使用StringBuilder 為什麼使用StringBuilder要從string對象的特性說起。 為什麼使用StringBuilder要從string對象的特性說起。 string對象在進行字元串拼接時,因為 ...
  • 簡介 簡介 對於.net來說,用web api來構建服務是一個不錯的選擇,都是http請求,調用簡單,但是如果真的要在程式中調用,則還有些工作要做,比如我們需要手寫httpClient調用,並映射Model, 如果服務少還可以,多了就繁瑣了。 Swagger Swagger 關於Swagger的信息 ...
  • 我們在上面對ASP.NET Core預設提供的具有跨平臺能力的KestrelServer進行了詳細介紹(《聊聊ASP.NET Core預設提供的這個跨平臺的伺服器——KestrelServer》),為了讓讀者朋友們對管道中的Server具有更加深刻的認識,接下來我們採用實例演示的形式創建一個自定義的 ...
  • 概述: ASP.NET Web API 的好用使用過的都知道,沒有複雜的配置文件,一個簡單的ApiController加上需要的Action就能工作。但是在使用API的時候總會遇到跨域請求的問題, 特別各種APP萬花齊放的今天,對API使用者身份角色驗證是不能避免的(完全開發的API不需要對使用者身 ...
  • 本節所謂的“配置同步”主要體現在兩個方面:其一,如何監控配置源併在其變化的時候自動載入其數據,其目的是讓應用中通過Configuration對象承載的配置與配置源的數據同步;其二、當Configuration對象承載的配置放生變換的時候如何嚮應用程式發送通知,最終讓應用程式使用最新的配置。 一、配置 ...
  • 本系列英文原文出自。 提示1. 在Entity Framework中怎樣排序關係(Relationships) 問題: 在Entity Framework論壇中常會看到關於排序相關聯項目的問題。 例如,想象你要查詢客戶,並返回那些欠款超過30的賬戶,與此同時檢索這些賬戶的訂單。 並且你需要將那些訂單 ...
  • 平時我們在用多線程開發的時候少不了Task,確實task給我們帶來了巨大的編程效率,在Task底層有一個TaskScheduler,它決定了task該如何被調度,而 在.net framework中有兩種系統定義Scheduler,第一個是Task預設的ThreadPoolTaskScheduler ...
  • 首先,通過NuGet添加NPOI. NPOI依賴SharpZipLib,通過NuGet添加SharpZipLib. 然後添加NPOI. 添加後項目的引用列表如下: 把DataTable轉換成Excel文件。 代碼如下: public static MemoryStream RenderDataTab ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...