索引 【無私分享:從入門到精通ASP.NET MVC】從0開始,一起搭框架、做項目 目錄索引 前言 前面還沒有下載到UI和資料庫的,這裡再次給大家提供一下:百度網盤 提取碼:fuuv ,UI是參照H+,但是H+是收費授權的(¥998RMB),價格有點貴,所以 我們的 UI 跟H+ 雖然是一個風格,但 ...
索引
【無私分享:從入門到精通ASP.NET MVC】從0開始,一起搭框架、做項目 目錄索引
前言
前面還沒有下載到UI和資料庫的,這裡再次給大家提供一下:百度網盤 提取碼:fuuv ,UI是參照H+,但是H+是收費授權的(¥998RMB),價格有點貴,所以 我們的 UI 跟H+ 雖然是一個風格,但是大家可以看到,CSS基本用的都是Bootstrap,JS 基本都是 最新的開源插件和自己重寫的,不存在版權問題。
我們前一章已經重寫了我們的倉儲類,文章中介面都已列出,實現類也說的很明白,引入 uow 後,大家修改一下原先的提交,就可以。但是很多朋友 總感覺 不給你文件 是因為 有些東西沒有放給你,那麼 就再次給大家 下載一下 我的倉儲,大家可以對比一下,是不是博客中故意少些東西。修改後的倉儲:百度網盤 提取碼:qw64
其實,只是想讓大家自己動手一下,修改方法很簡單,就是把我們之前的方法加上個條件: bool IsCommit=true,當我們只進行一項操作的時候,預設直接提交,當我們進行多項操作的時候,可以傳入false,不提交,然後通過uow 統一提交。大家可以看一下,使用的例子:
賣源碼?
很多朋友都在牢騷,說博主終於還是商業化了...
首先呢,到目前為止,我沒有賣一套源碼,如果你在我們的交流群里,你可以問問大家,很多私聊我買源碼的朋友,我都是跟他們說先按照博客園的文章自己做,學會才是目的,單純的源代碼是沒有任何意義的,博客園貼出的源碼跟我項目中源碼的唯一區別就是,我項目中的源碼沒有註釋,實在不行再來找我。
第二呢,有些源碼出售網站驚現 果凍博客源碼... 這讓我很吃驚,首先是受寵若驚,巧合的是,有個源碼網站是我朋友的,要不是他發給我我還真不知道,我是不反對這種行為的,你學會了就是你的,賣或不賣是你的事,但是扒下來的代碼,都沒有經過測試,這麼多錯誤,都跑不起來,就拿來出售,是很不地道的。
第三呢,我上面說過了,博客園貼出的源碼 跟我源碼的唯一區別就是,我項目中源碼是沒有這麼多註釋的。如果單純是分享源代碼,大可以放到GitHub上,難道一步一步貼出源代碼不就分享源碼,只有把完整的打個包發給每個人才叫分享源碼嗎?那博客園的意義是?博客園不是GitHub,兩個站的目的是不一樣的。對於同樣是新手的我來說,github上的純粹的源代碼,如果ReadMe 寫的不詳細,是很難看懂的,更不用說理解運用了,如果一篇一篇文章,一步一步解釋,一條一條註釋,然後貼出總體的,都不能理解的話,直接一個完整的源碼就能看懂嗎?
傷不起。。。
登錄
該正事了
登錄控制器 /Areas/SysManage/AccountController,一共有一個視圖,兩個方法:登錄頁面、登錄驗證、驗證碼。
首先,我們這個控制器跟區域里其它控制器的一個區別就是,我們沒有繼承 BaseController,我們可以看下我們的 BaseController 都幹了些什麼:
① 公用變數:主要就是用於試圖頁傳遞一些公用變數,例如:查詢關鍵字、分頁頁碼、分頁條數等。
② 用戶對象:網站後臺的管理員,我們首先從Session中獲取用戶,如果Session 失效,那麼我們從Cookies中獲取用戶信息,模擬登錄重新賦值 Session 並獲取用戶,如果Cookies也失效,那麼重新登錄。
③ 郵箱功能變數名稱:這個是內部郵件用的,我們這裡不用。
④ 登錄驗證
⑤ log4net日誌封裝方法
⑥ 輸出消息
⑦ 模塊許可權驗證:我們對每一個模塊都有獨立的許可權,並且監控Action和Method,在前面我們已經完成了對模塊許可權的初始化和自定義許可權擴展,這裡我們就需要驗證當前用戶,對此模塊的Action 是否有相應的操作許可權(例如:添加、修改、刪除、列表以及自定義的諸如 審核、列印、下載等),並且輸出許可權到視圖,同時在視圖頁對沒有相應許可權的按鈕Remove掉。通俗的講,就是我們Remove掉視圖頁中沒有許可權的按鈕,並且監控後臺Action的操作,所以即便你自己添加上相應的按鈕和方法,提交到後臺時也不會通過驗證。
通過上面詳細的解釋,我們可以發現,登錄頁是不需要這些的,但是後臺操作的其它控制器都需要,所以它們都繼承了BaseController 但是,登錄控制器不需要。
我們再回頭看我們的AccountController:
Index 這個沒什麼可解釋的,就是登陸頁面,我們只是執行了移除Session和Cookies操作。
我們來看下登錄驗證方法:
首先,我們是要驗證驗證碼。(不區分大小寫)if (!string.IsNullOrEmpty(code) && code.ToLower() == Session["gif"].ToString().ToLower())
然後,我們通過用戶輸入的賬號和密碼驗證用戶,這裡,我們通過匹配賬號和密碼返回用戶的實體類 var users = UserManage.UserLogin(item.ACCOUNT.Trim(), item.PASSWORD.Trim());
值得註意的是:因為我們用的加密演算法是動態密鑰的,所以對相同的字元串每次加密後的密文都是不一樣的,因此我們不能通過對用戶輸入的密碼進行加密後與數據匹配,而是通過賬號取出密碼,對密碼進行解密與用戶輸入匹配的方式驗證:
如果返回正常,我們首先還要驗證用戶是否被禁止登錄:
如果這一步驗證也通過,我們通過 var acconut = this.UserManage.GetAccountByUser(users); 獲取ViewModel:Account 類
1 public class Account 2 { 3 #region Attribute 4 /// <summary> 5 /// 主鍵 6 /// </summary> 7 public int Id { get; set; } 8 /// <summary> 9 /// 姓名 10 /// </summary> 11 public string Name { get; set; } 12 /// <summary> 13 /// 登錄的用戶名 14 /// </summary> 15 public string LogName { get; set; } 16 /// <summary> 17 /// 姓名拼音 18 /// </summary> 19 public string PinYin { get; set; } 20 /// <summary> 21 /// 登錄密碼 22 /// </summary> 23 public string PassWord { get; set; } 24 /// <summary> 25 /// 是否管理員 26 /// </summary> 27 public bool IsAdmin { get; set; } 28 /// <summary> 29 /// 用戶頭像 30 /// </summary> 31 public string Face_Img { get; set; } 32 /// <summary> 33 /// 部門職務 34 /// </summary> 35 36 public string Levels { get; set; } 37 /// <summary> 38 /// 用戶所屬系統Id 39 /// </summary> 40 public List<string> System_Id { get; set; } 41 /// <summary> 42 /// 用戶主部門 43 /// </summary> 44 public Domain.SYS_DEPARTMENT DptInfo { get; set; } 45 /// <summary> 46 /// 許可權集合 47 /// </summary> 48 public List<Domain.SYS_PERMISSION> Permissions { get; set; } 49 /// <summary> 50 /// 角色的集合 51 /// </summary> 52 public List<Domain.SYS_ROLE> Roles { get; set; } 53 /// <summary> 54 /// 用戶崗位集合 55 /// </summary> 56 public List<Domain.SYS_POST_USER> PostUser { get; set; } 57 /// <summary> 58 /// 用戶可操作的模塊集合 59 /// </summary> 60 public List<Domain.SYS_MODULE> Modules { get; set; } 61 #endregion 62 }
這個類裡面包含了用戶的基本信息和可操作的系統、模塊以及相應的許可權信息。
下一步,我們先來驗證一下,用戶可操作的系統(這裡起名有些誤導了,應該叫Systems,System_Id給人的印象是系統ID,而不是系統集合): if (acconut.System_Id.Count > 0)
單點登錄
如果可操作系統驗證通過,我們檢測一下配置文件是否開啟了單點登錄:單點登錄的實現方式其實很簡單,這裡大體跟大家說一下思路
首先,我們有個用戶線上狀態表 UserOnlie
當我們創建用戶的時候,這裡也會創建一個 一對一 的用戶線上狀態記錄。
我們在最外層的後臺主頁面中,有個 SignalR-Hubs ,也是與內部聊天室一體的,當用戶登錄後或重新連接時,我們便更新用戶的線上狀態:
當用戶離線時,我們更新用戶的線上狀態為離線:
通過這個簡單的方式,很簡陋的實現單用戶登錄模式。
OK,這樣基本的步驟就算完成了,如果用戶不線上或沒有開啟單用戶登錄,那麼我們記錄Session和Cookies,如果開啟了單用戶模式,並且用戶已線上,那麼我們登錄失敗,提示當前用戶,用戶已登錄
json.Msg = "當前用戶已登錄,系統不允許重覆登錄!登錄IP:" + UserOnline.UserIP;
這個Login方法大家可以修改一些串列的方法為非同步並行,提高效率。登錄頁的UI 在之前的文章以及本文頂部 已經給大家分享,源碼 在前面的文章中也有,但是沒有加入單點登錄,這個是後來加上的,這裡再給大家貼一下完整的登錄控制器:
1 using Common; 2 using Service.IService; 3 using System; 4 using System.Collections.Generic; 5 using System.Linq; 6 using System.Web; 7 using System.Web.Mvc; 8 9 namespace WebPage.Areas.SysManage.Controllers 10 { 11 public class AccountController : Controller 12 { 13 #region 聲明容器 14 /// <summary> 15 /// 用戶管理 16 /// add yuangang by 2016-05-16 17 /// </summary> 18 IUserManage UserManage { get; set; } 19 /// <summary> 20 /// 用戶線上管理 21 /// </summary> 22 IUserOnlineManage UserOnlineManage { get; set; } 23 /// <summary> 24 /// 日誌記錄 25 /// </summary> 26 log4net.Ext.IExtLog log = log4net.Ext.ExtLogManager.GetLogger("dblog"); 27 #endregion 28 29 #region 基本視圖 30 public ActionResult Index() 31 { 32 //移除Session 33 SessionHelper.Remove("CurrentUser"); 34 CookieHelper.ClearCookie("cookie_rememberme"); 35 return View(); 36 } 37 /// <summary> 38 /// 登錄驗證 39 /// add yuangang by 2016-05-16 40 /// </summary> 41 [ValidateAntiForgeryToken] 42 public ActionResult Login(Domain.SYS_USER item) 43 { 44 var json = new JsonHelper() { Msg = "登錄成功", Status = "n" }; 45 try 46 { 47 //獲取表單驗證碼 48 var code = Request.Form["code"]; 49 if (Session["gif"] != null) 50 { 51 //判斷用戶輸入的驗證碼是否正確 52 if (!string.IsNullOrEmpty(code) && code.ToLower() == Session["gif"].ToString().ToLower()) 53 { 54 //調用登錄驗證介面 返回用戶實體類 55 var users = UserManage.UserLogin(item.ACCOUNT.Trim(), item.PASSWORD.Trim()); 56 if (users != null) 57 { 58 //是否鎖定 59 if (users.ISCANLOGIN) 60 { 61 json.Msg = "用戶已鎖定,禁止登錄,請聯繫管理員進行解鎖"; 62 log.Warn(Utils.GetIP(), item.ACCOUNT, Request.Url.ToString(), "Login", "系統登錄,登錄結果:" + json.Msg); 63 return Json(json); 64 } 65 66 var acconut = this.UserManage.GetAccountByUser(users); 67 68 //系統訪問正常 69 if (acconut.System_Id.Count > 0) 70 { 71 //是否啟用單用戶登錄 72 if (System.Configuration.ConfigurationManager.AppSettings["IsSingleLogin"] == "True" ) 73 { 74 var UserOnline = UserOnlineManage.LoadListAll(p => p.FK_UserId == users.ID).FirstOrDefault(); 75 if(UserOnline!=null && UserOnline.IsOnline) 76 { 77 json.Msg = "當前用戶已登錄,系統不允許重覆登錄!登錄IP:" + UserOnline.UserIP; 78 log.Error(Utils.GetIP(), item.ACCOUNT, Request.Url.ToString(), "Login", "重覆登錄:" + json.Msg); 79 } 80 else 81 { 82 //寫入Session 當前登錄用戶 83 SessionHelper.SetSession("CurrentUser", acconut); 84 85 //記錄用戶信息到Cookies 86 string cookievalue = "{\"id\":\"" + acconut.Id + "\",\"username\":\"" + acconut.LogName + 87 "\",\"password\":\"" + acconut.PassWord + "\",\"ToKen\":\"" + 88 Session.SessionID + "\"}"; 89 CookieHelper.SetCookie("cookie_rememberme", new Common.CryptHelper.AESCrypt().Encrypt(cookievalue), 90 null); 91 92 json.Status = "y"; 93 json.ReUrl = "/Sys/Home/Index"; 94 log.Info(Utils.GetIP(), item.ACCOUNT, Request.Url.ToString(), "Login", "系統登錄,登錄結果:" + json.Msg); 95 } 96 } 97 else 98 { 99 //寫入Session 當前登錄用戶 100 SessionHelper.SetSession("CurrentUser", acconut); 101 102 //記錄用戶信息到Cookies 103 string cookievalue = "{\"id\":\"" + acconut.Id + "\",\"username\":\"" + acconut.LogName + 104 "\",\"password\":\"" + acconut.PassWord + "\",\"ToKen\":\"" + 105 Session.SessionID + "\"}"; 106 CookieHelper.SetCookie("cookie_rememberme", new Common.CryptHelper.AESCrypt().Encrypt(cookievalue), 107 null); 108 109 json.Status = "y"; 110 json.ReUrl = "/Sys/Home/Index"; 111 log.Info(Utils.GetIP(), item.ACCOUNT, Request.Url.ToString(), "Login", "系統登錄,登錄結果:" + json.Msg); 112 } 113 } 114 else 115 { 116 json.Msg = "站點來源不可信,系統拒絕登錄"; 117 log.Warn(Utils.GetIP(), "其他系統訪問者", "", "Login", "其他系統登錄失敗,原因:系統驗證錯誤,系統拒絕登錄"); 118 } 119 120 } 121 else 122 { 123 json.Msg = "用戶名或密碼不正確"; 124 log.Error(Utils.GetIP(), item.ACCOUNT, Request.Url.ToString(), "Login", "系統登錄,登錄結果:" + json.Msg); 125 } 126 } 127 else 128 { 129 json.Msg = "驗證碼不正確"; 130 log.Error(Utils.GetIP(), item.ACCOUNT, Request.Url.ToString(), "Login", "系統登錄,登錄結果:" + json.Msg); 131 } 132 } 133 else 134 { 135 json.Msg = "驗證碼已過期,請刷新驗證碼"; 136 log.Error(Utils.GetIP(), item.ACCOUNT, Request.Url.ToString(), "Login", "系統登錄,登錄結果:" + json.Msg); 137 } 138 } 139 catch (Exception e) 140 { 141 json.Msg = e.Message; 142 log.Error(Utils.GetIP(), item.ACCOUNT, Request.Url.ToString(), "Login", "系統登錄,登錄結果:" + json.Msg); 143 } 144 return Json(json, JsonRequestBehavior.AllowGet); 145 } 146 #endregion 147 148 #region 幫助方法 149 /// <summary> 150 /// 驗證碼 151 /// </summary> 152 public FileContentResult ValidateCode() 153 { 154 string code = ""; 155 System.IO.MemoryStream ms = new Models.verify_code().Create(out code); 156 Session["gif"] = code;//驗證碼存儲在Session中,供驗證。 157 Response.ClearContent();//清空輸出流 158 return File(ms.ToArray(), @"image/png"); 159 } 160 #endregion 161 } 162 }View Code