Hi,
你們好,仍是星期五,仍是Rector,又在圖享網準時和你們見面了。
今天給你們帶來系列教程《一步一步建立ASP.NET MVC5程序[Repository+Autofac+Automapper+SqlSugar]》的第八期了,不知道你有沒有按照教程將前七期的都實際練習一篇呢?若是是,你在練習的時候有沒有遇到什麼問題呢?
反正Rector是有收到部分童鞋發來他們練習過程當中的問題反饋的哦。css
若是你仔細閱讀並實際練習了前面七期的教程,我相信,做爲剛入門或者經驗尚淺的你必定會有收穫的。html
加油吧,騷年!!! 人生苦短,就怕努力!!!mysql
Rector這是要成爲心理導師的節奏啊,一來就給你們灌飽心靈雞湯。。。jquery
**本文篇幅有點長,請做好內心準備!!!
同時,也吐個槽,本文看似內容簡單的一B,但也花了筆者幾個小時來準備示例以及寫做,寫技術文章真心傷不起
珍愛生命,遠離程序!!!
**git
仍是回到咱們的正題,開始咱們今天的系列教程:《一步一步建立ASP.NET MVC5程序Repository+Autofac+Automapper+SqlSugar》github
這個表呢,Rector已經爲你們準備好了,MySQL表結構以下:web
SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for ts_user -- ---------------------------- DROP TABLE IF EXISTS `tb_user`; CREATE TABLE `tb_user` ( `Id` int(10) NOT NULL AUTO_INCREMENT, `LoginName` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '登陸名', `Password` varchar(150) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '密碼', `DisplayName` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '顯示名稱', `RealName` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '真實姓名', `EmailAddress` varchar(120) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '電子郵箱', `Avatar` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '用戶頭像', `Status` int(2) NOT NULL DEFAULT 1 COMMENT '用戶的狀態,0:禁用,1:正常', `Telephone` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '手機號碼', `Qq` varchar(15) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '', `WebsiteUrl` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '', `CreatedOn` datetime(0) NULL DEFAULT NULL COMMENT '用戶建立時間', `CreatedIp` varchar(24) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '建立用戶時的IP地址', `LoginCount` int(8) NULL DEFAULT 0 COMMENT '登陸次數累加器', `LatestLoginDate` datetime(0) NULL DEFAULT NULL COMMENT '最近一次登陸時間', `LatestLoginIp` varchar(24) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '最近一次登陸時的IP地址', `ModifiedOn` datetime(0) NULL DEFAULT NULL COMMENT '最近修改時間', `Type` int(2) NULL DEFAULT 0 COMMENT '用戶類型[-1:超級管理員,0:通常用戶]', PRIMARY KEY (`Id`) USING BTREE, UNIQUE INDEX `IX_LoginName`(`LoginName`) USING BTREE, UNIQUE INDEX `IX_EmailAddress`(`EmailAddress`) USING BTREE, INDEX `IX_CreatedOn`(`CreatedOn`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 0 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; SET FOREIGN_KEY_CHECKS = 1;
請直接複製以上MySQL腳本,而後到對應數據執行便可,固然你也能夠在這個版本的源碼裏面找到。
這個表就不許備提早寫入示例數據了,一會咱們用註冊功能來寫入數據。sql
在項目 【TsBlog.Domain】中的Entities文件夾中建立 User.cs 實體類:數據庫
using SqlSugar; using System; namespace TsBlog.Domain.Entities { [SugarTable("tb_user")] public class User { [SugarColumn(IsIdentity = true, IsPrimaryKey = true)] public int Id { get; set; } public string LoginName { get; set; } public string Password { get; set; } public string RealName { get; set; } public string EmailAddress { get; set; } public string Avatar { get; set; } public int Status { get; set; } public string Telephone { get; set; } public string Qq { get; set; } public string WebsiteUrl { get; set; } public DateTime CreatedOn { get; set; } public string CreatedIp { get; set; } public int LoginCount { get; set; } public DateTime? LatestLoginDate { get; set; } public string LatestLoginIp { get; set; } public DateTime? ModifiedOn { get; set; } public int Type { get; set; } } }
再在項目【TsBlog.ViewModel】中建立 User 的文件夾,並建立如下幾個視圖實體類bootstrap
LoginViewModel.cs
using System.ComponentModel.DataAnnotations; namespace TsBlog.ViewModel.User { /// <summary> /// 用戶登陸視圖實體 /// </summary> public class LoginViewModel { [Required(ErrorMessage = "請輸入用戶")] [Display(Name = "用戶名")] public string UserName { get; set; } [Required(ErrorMessage = "請輸入密碼")] [Display(Name = "密碼")] [DataType(DataType.Password)] public string Password { get; set; } } }
RegisterViewModel.cs
using System.ComponentModel.DataAnnotations; namespace TsBlog.ViewModel.User { /// <summary> /// 用戶註冊視圖實體 /// </summary> public class RegisterViewModel { [Required(ErrorMessage = "請輸入用戶名")] [Display(Name = "用戶名")] public string UserName { get; set; } [Required(ErrorMessage = "請輸入密碼")] [Display(Name = "密碼")] [DataType(DataType.Password), MaxLength(20, ErrorMessage = "密碼最大長度爲20個字符"), MinLength(6, ErrorMessage = "密碼最小長度爲6個字符")] public string Password { get; set; } [Required(ErrorMessage = "請輸入確認密碼")] [Display(Name = "確認密碼")] [DataType(DataType.Password), Compare("Password", ErrorMessage = "兩次密碼不一致")] public string ConfirmPassword { get; set; } } }
UserViewModel.cs:
using System; namespace TsBlog.ViewModel.User { /// <summary> /// 與領域用戶實體對應的用戶視圖實體 /// </summary> public class UserViewModel { public int Id { get; set; } public string LoginName { get; set; } public string Password { get; set; } public string RealName { get; set; } public string EmailAddress { get; set; } public string Avatar { get; set; } public int Status { get; set; } public string Telephone { get; set; } public string Qq { get; set; } public string WebsiteUrl { get; set; } public DateTime CreatedOn { get; set; } public string CreatedIp { get; set; } public int LoginCount { get; set; } public DateTime? LatestLoginDate { get; set; } public string LatestLoginIp { get; set; } public DateTime? ModifiedOn { get; set; } public int Type { get; set; } } }
在項目【TsBlog.Repositories】中建立 IUserRepository.cs 以及其實現類 UserRepository.cs。
IUserRepository.cs:
using TsBlog.Domain.Entities; namespace TsBlog.Repositories { public interface IUserRepository : IRepository<User> { } }
UserRepository.cs:
using TsBlog.Domain.Entities; namespace TsBlog.Repositories { public class UserRepository : GenericRepository<User>, IUserRepository { } }
在項目【TsBlog.Services】中建立 IUserService.cs 以及其實現類 UserService.cs。
IUserService.cs:
using TsBlog.Domain.Entities; namespace TsBlog.Services { public interface IUserService : IService<User> { User FindByLoginName(string loginName); } }
UserService.cs:
using TsBlog.Domain.Entities; using TsBlog.Repositories; namespace TsBlog.Services { public class UserService : GenericService<User>, IUserService { private readonly IUserRepository _repository; public UserService(IUserRepository repository) : base(repository) { _repository = repository; } public User FindByLoginName(string loginName) { return _repository.FindByClause(x => x.LoginName == loginName); } } }
在解決方案文件夾【1.Libraries】中建立一個新的項目,取名爲【TsBlog.Core】,在此項目中先建立一個名爲 Security的文件夾,再建立一個加密類 Encryptor.cs:
using System.Security.Cryptography; using System.Text; namespace TsBlog.Core.Security { /// <summary> /// 加密靜態類 /// </summary> public static class Encryptor { //MD5加密一個字符串 public static string Md5Hash(string text) { MD5 md5 = new MD5CryptoServiceProvider(); md5.ComputeHash(Encoding.ASCII.GetBytes(text)); var result = md5.Hash; var strBuilder = new StringBuilder(); foreach (var t in result) { strBuilder.Append(t.ToString("x2")); } return strBuilder.ToString(); } } }
在用戶註冊或者登陸時,咱們將使用這個MD5加密用戶的密碼,並將其保存到數據庫中(數據庫中保存明文的密碼是很是危險的,特別是在重要的安全級別很高的項目中,千(不)萬(信)別(你)這(試)樣(一)作(下)!!!)。
在項目【TsBlog.Frontend】中建立控制器 AccountController.cs,並添加以下代碼:
AccountController.cs
using System; using System.Web.Mvc; using TsBlog.Core.Security; using TsBlog.Domain.Entities; using TsBlog.Services; using TsBlog.ViewModel.User; namespace TsBlog.Frontend.Controllers { /// <summary> /// 用戶中心控制器 /// </summary> public class AccountController : Controller { /// <summary> /// 用戶服務接口 /// </summary> private readonly IUserService _userService; public AccountController(IUserService userService) { _userService = userService; } /// <summary> /// 登陸頁面 /// </summary> /// <returns></returns> public ActionResult Login() { return View(); } /// <summary> /// 提交登陸請求 /// </summary> /// <param name="model"></param> /// <returns></returns> [HttpPost, ValidateAntiForgeryToken, AllowAnonymous] public ActionResult Login(LoginViewModel model) { //若是視圖模型中的屬性沒有驗證經過,則返回到登陸頁面,要求用戶從新填寫 if (!ModelState.IsValid) { return View(model); } //根據用戶登陸名查詢指定用戶實體 var user = _userService.FindByLoginName(model.UserName.Trim()); //若是用戶不存在,則攜帶錯誤消息並返回登陸頁面 if (user == null) { ModelState.AddModelError("error_message", "用戶不存在"); return View(model); } //若是密碼不匹配,則攜帶錯誤消息並返回登陸頁面 if (user.Password != Encryptor.Md5Hash(model.Password.Trim())) { ModelState.AddModelError("error_message", "密碼錯誤,請從新登陸"); return View(model); } //並用戶實體保存到Session中 Session["user_account"] = user; //跳轉到首頁 return RedirectToAction("index", "home"); } /// <summary> /// 註冊頁面 /// </summary> /// <returns></returns> public ActionResult Register() { return View(); } /// <summary> /// 提交註冊請求 /// </summary> /// <param name="model"></param> /// <returns></returns> [HttpPost, ValidateAntiForgeryToken, AllowAnonymous] public ActionResult Register(RegisterViewModel model) { //若是視圖模型中的屬性沒有驗證經過,則返回到註冊頁面,要求用戶從新填寫 if (!ModelState.IsValid) { return View(model); } //建立一個用戶實體 var user = new User { LoginName = model.UserName, Password = Encryptor.Md5Hash(model.Password.Trim()), CreatedOn = DateTime.Now //因爲是示例教程,因此其餘字段不做填充了 }; //將用戶實體對象寫入數據庫中 var ret = _userService.Insert(user); if (ret <= 0) { //若是註冊失敗,則攜帶錯誤消息並返回註冊頁面 ModelState.AddModelError("error_message", "註冊失敗"); return View(model); } //若是註冊成功,則跳轉到登陸頁面 return RedirectToAction("login"); } } }
因爲以前咱們將項目中的多餘的JS庫所有移除掉了,因此如今咱們從新安裝一下咱們項目中將要到的一些JS庫,包括:jQuery,Bootstrap等,都使用Nuget來安裝,方便統一管理和升級。
安裝jQuery:
安裝Bootstrap:
安裝jquery.validate.bootstrap:
安裝完成後的JS庫文件夾:
在 [Views/Account]文件夾中建立註冊頁面視圖 register.cshtml:
@model TsBlog.ViewModel.User.RegisterViewModel @{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>用戶註冊</title> <style type="text/css"> * { box-sizing: border-box; } body { box-sizing: border-box; margin: 0; padding: 0; color: #333; } .account-container { position: absolute; margin: auto; top: 0; right: 0; bottom: 0; left: 0; width: 400px; height: 480px; background-color: #fff; /*border-radius: 3px;*/ box-shadow: 0 2px 2px 0 rgba(0,0,0,0.14), 0 3px 1px -2px rgba(0,0,0,0.12), 0 1px 5px 0 rgba(0,0,0,0.2); } .account-signin-container { margin-top: 15px; } .account-signin-container h1 { font-size: 20px; border-bottom: 2px solid #f7f7f7; margin: 0 0 15px; padding-bottom: 10px; padding-left: 15px; letter-spacing: 0.1em; } .account-form { padding: 15px; } .account-form .form-group { width: 100%; margin-bottom: 15px; } .account-form .form-group label { width: 100%; display: block; } .account-form .form-group input { border: 1px solid #ccc; line-height: 32px; font-size: 16px; padding: 2px 0px; padding-left: 5px; display: block; width: 100%; margin-top: 5px; } .account-form #btn_register { border: 0; background: #3b78e7; color: #fff; font-size: 18px; font-weight: bold; padding: 8px 25px; cursor: pointer; margin-top: 15px; display: inline-block; box-shadow: 0 2px 2px 0 rgba(0,0,0,0.14), 0 3px 1px -2px rgba(0,0,0,0.12), 0 1px 5px 0 rgba(0,0,0,0.2); border-radius: 3px; min-width: 100px; text-align: center; } .account-form #btn_register:hover { background: #4885F3; } span.error { color: #f00; } .btn-login { float: right; display: block; margin-top: 25px; color: #4885f3; } @@media(max-width:500px) { .account-container { width: 100%; height: 100vh; } } </style> </head> <body> <div class="account-container"> <div class="account-modal-container"> <div class="modal"></div> <div class="load-bar-container"> <div class="load-bar"> <div class="bar"></div> <div class="bar"></div> <div class="bar"></div> </div> </div> <div class="account-signin-container"> <h1>用戶註冊</h1> @using (Html.BeginForm("register", "account", FormMethod.Post, new { @class = "account-form", role = "form" })) { @Html.ValidationMessage("error_message", new { @class = "error" }) @Html.AntiForgeryToken() <div class="form-group"> <label> <span>登陸名:</span> @Html.TextBoxFor(m => m.UserName, new { placeholder = "請輸入登陸名" }) @Html.ValidationMessageFor(m => m.UserName, "", new { @class = "error" }) </label> </div> <div class="form-group"> <label> <span>密碼:</span> @Html.PasswordFor(m => m.Password, new { placeholder = "請輸入密碼" }) @Html.ValidationMessageFor(m => m.Password, "", new { @class = "error" }) </label> </div> <div class="form-group"> <label> <span>確認密碼:</span> @Html.PasswordFor(m => m.ConfirmPassword, new { placeholder = "請輸入確認密碼" }) @Html.ValidationMessageFor(m => m.ConfirmPassword, "", new { @class = "error" }) </label> </div> <div class="form-group"> <button id="btn_register" type="submit">注 冊</button> <a class="btn-login" href="~/account/login">登陸</a> </div> } </div> </div> </div> <script src="~/Scripts/jquery-3.2.1.min.js"></script> <script src="~/Scripts/jquery.validate.min.js"></script> <script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script> </body> </html>
再在當前文件夾下建立 login.cshtml 視圖文件用做登陸頁面:
@model TsBlog.ViewModel.User.LoginViewModel @{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>用戶登陸</title> <style type="text/css"> * { box-sizing: border-box; } body { box-sizing: border-box; margin: 0; padding: 0; color: #333; } .account-container { position: absolute; margin: auto; top: 0; right: 0; bottom: 0; left: 0; width: 400px; height: 450px; background-color: #fff; /*border-radius: 3px;*/ box-shadow: 0 2px 2px 0 rgba(0,0,0,0.14), 0 3px 1px -2px rgba(0,0,0,0.12), 0 1px 5px 0 rgba(0,0,0,0.2); } .account-signin-container { margin-top: 15px; } .account-signin-container h1 { font-size: 20px; border-bottom: 2px solid #f7f7f7; margin: 0 0 15px; padding-bottom: 10px; padding-left: 15px; letter-spacing: 0.1em; } .account-form { padding: 15px; } .account-form .form-group { width: 100%; margin-bottom: 15px; } .account-form .form-group label { width: 100%; display: block; } .account-form .form-group input { border: 1px solid #ccc; line-height: 32px; font-size: 16px; padding: 2px 0px; padding-left: 5px; display: block; width: 100%; margin-top: 5px; } .account-form #btn_login { border: 0; background: #3b78e7; color: #fff; font-size: 18px; font-weight: bold; padding: 8px 25px; cursor: pointer; margin-top: 15px; display: inline-block; box-shadow: 0 2px 2px 0 rgba(0,0,0,0.14), 0 3px 1px -2px rgba(0,0,0,0.12), 0 1px 5px 0 rgba(0,0,0,0.2); border-radius: 3px; min-width: 100px; text-align: center; } .account-form #btn_login:hover { background: #4885F3; } span.error { color: #f00; } .btn-register { float: right; display: block; margin-top: 25px; color: #4885f3; } @@media(max-width:500px) { .account-container { width: 100%; height: 100vh; } } </style> </head> <body> <div class="account-container"> <div class="account-modal-container"> <div class="modal"></div> <div class="load-bar-container"> <div class="load-bar"> <div class="bar"></div> <div class="bar"></div> <div class="bar"></div> </div> </div> <div class="account-signin-container"> <h1>用戶登陸</h1> @using (Html.BeginForm("login", "account", FormMethod.Post, new { @class = "account-form", role = "form" })) { @Html.ValidationMessage("error_message", new { @class = "error" }) @Html.AntiForgeryToken() <div class="form-group"> <label> <span>登陸名:</span> @Html.TextBoxFor(m => m.UserName, new { placeholder = "請輸入登陸名" }) @Html.ValidationMessageFor(m => m.UserName, "", new { @class = "error" }) </label> </div> <div class="form-group"> <label> <span>密碼:</span> @Html.PasswordFor(m => m.Password, new { placeholder = "請輸入密碼" }) @Html.ValidationMessageFor(m => m.Password, "", new { @class = "error" }) </label> </div> <div class="form-group"> <button id="btn_login" type="submit">登 錄</button> <a class="btn-register" href="~/account/register">註冊帳號</a> </div> } </div> </div> </div> <script src="~/Scripts/jquery-3.2.1.min.js"></script> <script src="~/Scripts/jquery.validate.min.js"></script> <script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script> <script src="~/res/assets/notie/notie.min.js"></script> </body> </html>
這兩個頁面均是響應式的佈局,可適應不一樣設備。
好了,關於註冊和登陸的邏輯以及頁面都完成了,那麼運行項目,打開註冊頁面:http://localhost:54739/account/register,具體的註冊請自行體驗:
註冊成功後,系統將帶你到登陸頁面:
具體功能也請自行體驗。
以上,咱們只完成了註冊和登陸的基本功能,接下來咱們來體驗一下簡單的權限訪問,在本期教程以前,咱們的: http://localhost:54739/home/index 以及 http://localhost:54739/home/post 是能夠直接訪問的,如今咱們給這兩個頁面添加訪問權限,即只有登陸後才能訪問,修改 HomeController.cs 以下:
using System.Web.Mvc; using TsBlog.AutoMapperConfig; using TsBlog.Services; namespace TsBlog.Frontend.Controllers { public class HomeController : Controller { private readonly IPostService _postService; public HomeController(IPostService postService) { _postService = postService; } public ActionResult Index() { //若是未登陸,則跳轉到登陸頁面 if (Session["user_account"] == null) { return RedirectToAction("login", "account"); } return View(); } public ActionResult Post() { //若是未登陸,則跳轉到登陸頁面 if (Session["user_account"] == null) { return RedirectToAction("login", "account"); } var post = _postService.FindById(1).ToModel(); return View(post); } } }
從新編譯項目,按F5運行,再打開地址:http://localhost:54739/home/index ,發生了什麼狀況?
是否是被重定向到了登陸頁面,要求你登陸?
這就對了,輸入你剛纔註冊的用戶名和密碼,登陸後,系統會從新帶你到:http://localhost:54739/home/index 頁面。
OK,今天這期的關於用戶註冊和登陸功能就介紹到這裏,本期只實現了簡單的功能,在後續的教程中將重構和封裝相應的功能代碼,敬請期待。。。
本期源碼託管地址:https://github.com/lampo1024/...
數據庫腳本文件請到目錄下找:TsBlogdocumentscriptsmysqlv1.8\
若是你喜歡Rector的本系列文章,請爲我點個大大的贊。
看完教程若是以爲還不過癮的,遇到問題的,想「勾對」的,歡迎加入圖享網官方QQ羣:483350228。有什麼,你懂的。。。
謝謝你的耐心閱讀,未完待續,咱們下期再見……
本文來源自 碼友網 《一步一步建立ASP.NET MVC5程序[Repository+Autofac+Automapper+SqlSugar](八)》