摘要:在ASP.NET MVC5中建置以角色為基礎的授權機制
測試環境: VS2013、MVC5、Windows7
在前一篇貼文中,已探索過如何在MVC5中自定ASP.NET Identity,接下來要來試試在MVC5中如何運用 ASP.NET Identity來設定一個以 "角色"為基礎的授權機制。為了方便起見,簡化了這個認證機制的內容,同時假設這是一個公司內部使用的應用程式,所以拿掉了"註冊"的功能,所有的使用帳號管理都必須透過某一管理權限(Admin)的使用者來進行,也就是說只有具備有 Admin 角色的使用者可以執行”帳戶管理"的功能。
貼文內容:
-
建立MVC5新專案
-
修改相關 Models
-
擴展Identity Management Model
-
加入新欄位
-
建立Helper Class
-
-
擴展Account Management ViewModels (AccountViewModels.cs)
-
在RegisterViewModel加入新欄位 及 GetUser method
-
新增 EditUserViewModel、SelectUserRolesViewModel、SelectRoleEditorViewModel
-
-
-
修改相關 Controllers
-
修改AccountController 中 Register Method 加入 Authorize attribute
-
加入 Index Method (ActionResult)
-
加入 Edit Method (ActionResult)
-
加入 Delete Method (ActionResult)
-
加入 UserRoles Method (ActionResult)
-
-
修改相關 Views
-
修改Register.cshtml View
-
新增Edit、Delete、Index 等方法的Views
-
新增UserRoles.cshtml View 並 新增程式碼
-
新增 SelectRoleEditorViewModel.cshtml 在 Shared/EditorTemplates目錄下
-
-
在主頁面上新增”帳號管理" 功能按鈕
-
移除主頁面上的註冊功能
-
啟動 Migration功能
-
在Seed()方法中加入建立測試資料的程式碼
-
更新資料庫
-
執行結果
建立MVC5新專案
修改相關 Models
1. 擴展Identity Management Model (IdentityModels.cs)
-
加入新欄位:為使用者資料多加三個屬性欄位,分別是FirstName、LastName、Email。
-
建立Helper Class:利用Asp.Net Identity API建立一個 Identity Management Helper class: IdentityManager class,包含有建立角色、建立使用者...等功能。
IdentityModels.cs 完整程式
using Microsoft.AspNet.Identity; using Microsoft.AspNet.Identity.EntityFramework; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; namespace RoleBaseProject.Models { // You can add profile data for the user by adding more properties to your ApplicationUser class, please visit http://go.microsoft.com/fwlink/?LinkID=317594 to learn more. public class ApplicationUser : IdentityUser { [Required] public string FirstName { get; set; } [Required] public string LastName { get; set; }
[Required] public string Email { get; set; } } public class ApplicationDbContext : IdentityDbContext<ApplicationUser> { public ApplicationDbContext() : base("DefaultConnection") { } } public class IdentityManager { // 判斷角色是否已在存在 public bool RoleExists(string name) { var rm = new RoleManager<IdentityRole>( new RoleStore<IdentityRole>(new ApplicationDbContext())); return rm.RoleExists(name); } // 新增角色 public bool CreateRole(string name) { var rm = new RoleManager<IdentityRole>( new RoleStore<IdentityRole>(new ApplicationDbContext())); var idResult = rm.Create(new IdentityRole(name)); return idResult.Succeeded; } // 新增角色 public bool CreateUser(ApplicationUser user, string password) { var um = new UserManager<ApplicationUser>( new UserStore<ApplicationUser>(new ApplicationDbContext())); var idResult = um.Create(user, password); return idResult.Succeeded; } // 將使用者加入角色中 public bool AddUserToRole(string userId, string roleName) { var um = new UserManager<ApplicationUser>( new UserStore<ApplicationUser>(new ApplicationDbContext())); var idResult = um.AddToRole(userId, roleName); return idResult.Succeeded; } // 清除使用者的角色設定 public void ClearUserRoles(string userId) { var um = new UserManager<ApplicationUser>( new UserStore<ApplicationUser>(new ApplicationDbContext())); var user = um.FindById(userId); var currentRoles = new List<IdentityUserRole>(); currentRoles.AddRange(user.Roles); foreach(var role in currentRoles) { um.RemoveFromRole(userId, role.Role.Name); } } } } |
2. 擴展Account Management ViewModels (AccountViewModels.cs)
-
在RegisterViewModel加入新欄位 及 GetUser method
-
針對要新增的"帳號管理"功能新增三個ViewModel,分別是: EditUserViewModel、SelectUserRolesViewModel、SelectRoleEditorViewModel
AccountViewModels.cs 完整程式
using Microsoft.AspNet.Identity.EntityFramework; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; namespace RoleBaseProject.Models { public class ExternalLoginConfirmationViewModel { [Required] [Display(Name = "使用者名稱")] public string UserName { get; set; } } public class ManageUserViewModel { [Required] [DataType(DataType.Password)] [Display(Name = "目前密碼")] public string OldPassword { get; set; } [Required] [StringLength(100, ErrorMessage = "{0} 的長度至少必須為 {2} 個字元。", MinimumLength = 6)] [DataType(DataType.Password)] [Display(Name = "新密碼")] public string NewPassword { get; set; } [DataType(DataType.Password)] [Display(Name = "確認新密碼")] [Compare("NewPassword", ErrorMessage = "新密碼與確認密碼不相符。")] public string ConfirmPassword { get; set; } } public class LoginViewModel { [Required] [Display(Name = "使用者名稱")] public string UserName { get; set; } [Required] [DataType(DataType.Password)] [Display(Name = "密碼")] public string Password { get; set; } [Display(Name = "記住我?")] public bool RememberMe { get; set; } } public class RegisterViewModel { [Required] [Display(Name = "使用者名稱")] public string UserName { get; set; } [Required] [StringLength(100, ErrorMessage = "{0} 的長度至少必須為 {2} 個字元。", MinimumLength = 6)] [DataType(DataType.Password)] [Display(Name = "密碼")] public string Password { get; set; } [DataType(DataType.Password)] [Display(Name = "確認密碼")] [Compare("Password", ErrorMessage = "密碼和確認密碼不相符。")] public string ConfirmPassword { get; set; } [Required] [Display(Name = "First Name")] public string FirstName { get; set; } [Required] [Display(Name = "Last Name")] public string LastName { get; set; } [Required] [Display(Name = "電子郵件信箱")] public string Email { get; set; } public ApplicationUser GetUser() { var user = new ApplicationUser() { UserName = this.UserName, FirstName = this.FirstName, LastName = this.LastName, Email = this.Email, }; return user; } } public class EditUserViewModel { public EditUserViewModel() { } // Allow Initialization with an instance of ApplicationUser: public EditUserViewModel(ApplicationUser user) { this.UserName = user.UserName; this.FirstName = user.FirstName; this.LastName = user.LastName; this.Email = user.Email; } [Required] [Display(Name = "使用者帳號")] public string UserName { get; set; } [Required] [Display(Name = "名")] public string FirstName { get; set; } [Required] [Display(Name = "姓")] public string LastName { get; set; } [Required] [Display(Name = "電子郵件信箱")] public string Email { get; set; } } public class SelectUserRolesViewModel { public SelectUserRolesViewModel() { this.Roles = new List<SelectRoleEditorViewModel>(); } // Enable initialization with an instance of ApplicationUser: public SelectUserRolesViewModel(ApplicationUser user) : this() { this.UserName = user.UserName; this.FirstName = user.FirstName; this.LastName = user.LastName; var Db = new ApplicationDbContext(); // Add all available roles to the list of EditorViewModels: var allRoles = Db.Roles; foreach (var role in allRoles) { // An EditorViewModel will be used by Editor Template: var rvm = new SelectRoleEditorViewModel(role); this.Roles.Add(rvm); } // Set the Selected property to true for those roles for // which the current user is a member: foreach (var userRole in user.Roles) { var checkUserRole = this.Roles.Find(r => r.RoleName == userRole.Role.Name); checkUserRole.Selected = true; } } public string UserName { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public List<SelectRoleEditorViewModel> Roles { get; set; } } // Used to display a single role with a checkbox, within a list structure: public class SelectRoleEditorViewModel { public SelectRoleEditorViewModel() { } public SelectRoleEditorViewModel(IdentityRole role) { this.RoleName = role.Name; } public bool Selected { get; set; } [Required] public string RoleName { get; set; } } } |
修改相關 Controllers
-
修改AccountController 中 Register Method 加入 Authorize attribute
必須具有Admin 角色者才能執行。
-
加入 Index Method (ActionResult)
[Authorize(Roles = "Admin")] public ActionResult Index() { var Db = new ApplicationDbContext(); var users = Db.Users; var model = new List<EditUserViewModel>(); foreach(var user in users) { var u = new EditUserViewModel(user); model.Add(u); } return View(model); } |
-
加入 Edit Method (ActionResult)
// // GEG: /Account/Edit [Authorize(Roles = "Admin")] public ActionResult Edit(string id , ManageMessageId? Message = null) { var Db = new ApplicationDbContext(); var user = Db.Users.First(u => u.UserName == id); var model = new EditUserViewModel(user); ViewBag.MessageId = Message; return View(model); } // // POST: /Account/Edit [HttpPost] [Authorize(Roles = "Admin")] [ValidateAntiForgeryToken] public async Task<ActionResult> Edit(EditUserViewModel model) { if (ModelState.IsValid) { var Db = new ApplicationDbContext(); var user = Db.Users.First(u => u.UserName == model.UserName); user.FirstName = model.FirstName; user.LastName = model.LastName; user.Email = model.Email; Db.Entry(user).State = System.Data.Entity.EntityState.Modified; await Db.SaveChangesAsync(); return RedirectToAction("Index"); } return View(model); } |
-
加入 Delete Method (ActionResult)
// // GEG: /Account/Delete [Authorize(Roles="Admin")] public ActionResult Delete(string id = null) { var Db = new ApplicationDbContext(); var user = Db.Users.First(u => u.UserName == id); var model = new EditUserViewModel(user); return View(model); } // // POST: /Account/Delete [HttpPost, ActionName("Delete")] [Authorize(Roles = "Admin")] [ValidateAntiForgeryToken] public ActionResult DeleteConfirmed(string id) { var Db = new ApplicationDbContext(); var user = Db.Users.First(u => u.UserName == id); Db.Users.Remove(user); Db.SaveChanges(); return RedirectToAction("Index"); } |
-
加入 UserRoles Method (ActionResult)
// // GEG: /Account/UserRoles [Authorize(Roles = "Admin")] public ActionResult UserRoles(string id) { var Db = new ApplicationDbContext(); var user = Db.Users.First(u => u.UserName == id); var model = new SelectUserRolesViewModel(user); return View(model); } // // POST: /Account/UserRoles [HttpPost] [Authorize(Roles = "Admin")] [ValidateAntiForgeryToken] public ActionResult UserRoles(SelectUserRolesViewModel model) { if (ModelState.IsValid) { var idManager = new IdentityManager(); var Db = new ApplicationDbContext(); var user = Db.Users.First(u => u.UserName == model.UserName); idManager.ClearUserRoles(user.Id); foreach (var role in model.Roles) { if (role.Selected) { idManager.AddUserToRole(user.Id, role.RoleName); } } return RedirectToAction("index"); } return View(); } |
AccountController.cs 完整程式
using System; using System.Collections.Generic; using System.Linq; using System.Security.Claims; using System.Threading.Tasks; using System.Web; using System.Web.Mvc; using Microsoft.AspNet.Identity; using Microsoft.AspNet.Identity.EntityFramework; using Microsoft.Owin.Security; using RoleBaseProject.Models; namespace RoleBaseProject.Controllers { [Authorize] public class AccountController : Controller { public AccountController() : this(new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()))) { } public AccountController(UserManager<ApplicationUser> userManager) { UserManager = userManager; } public UserManager<ApplicationUser> UserManager { get; private set; } // // GET: /Account/Login [AllowAnonymous] public ActionResult Login(string returnUrl) { ViewBag.ReturnUrl = returnUrl; return View(); } // // POST: /Account/Login [HttpPost] [AllowAnonymous] [ValidateAntiForgeryToken] public async Task<ActionResult> Login(LoginViewModel model, string returnUrl) { if (ModelState.IsValid) { var user = await UserManager.FindAsync(model.UserName, model.Password); if (user != null) { await SignInAsync(user, model.RememberMe); return RedirectToLocal(returnUrl); } else { ModelState.AddModelError("", "Invalid username or password."); } } // 如果執行到這裡,發生某項失敗,則重新顯示表單 return View(model); } // // GET: /Account/Register [Authorize(Roles="Admin")] public ActionResult Register() { return View(); } // // POST: /Account/Register [HttpPost] [Authorize(Roles = "Admin")] [ValidateAntiForgeryToken] public async Task<ActionResult> Register(RegisterViewModel model) { if (ModelState.IsValid) { var user = new ApplicationUser() { UserName = model.UserName, FirstName = model.FirstName, LastName = model.LastName, Email = model.Email, }; var result = await UserManager.CreateAsync(user, model.Password); if (result.Succeeded) { await SignInAsync(user, isPersistent: false); return RedirectToAction("Index", "Home"); } else { AddErrors(result); } } // 如果執行到這裡,發生某項失敗,則重新顯示表單 return View(model); } // // GEG: /Account/Index [Authorize(Roles = "Admin")] public ActionResult Index() { var Db = new ApplicationDbContext(); var users = Db.Users; var model = new List<EditUserViewModel>(); foreach(var user in users) { var u = new EditUserViewModel(user); model.Add(u); } return View(model); } // // GEG: /Account/Edit [Authorize(Roles = "Admin")] public ActionResult Edit(string id , ManageMessageId? Message = null) { var Db = new ApplicationDbContext(); var user = Db.Users.First(u => u.UserName == id); var model = new EditUserViewModel(user); ViewBag.MessageId = Message; return View(model); } // // POST: /Account/Edit [HttpPost] [Authorize(Roles = "Admin")] [ValidateAntiForgeryToken] public async Task<ActionResult> Edit(EditUserViewModel model) { if (ModelState.IsValid) { var Db = new ApplicationDbContext(); var user = Db.Users.First(u => u.UserName == model.UserName); user.FirstName = model.FirstName; user.LastName = model.LastName; user.Email = model.Email; Db.Entry(user).State = System.Data.Entity.EntityState.Modified; await Db.SaveChangesAsync(); return RedirectToAction("Index"); } return View(model); } // // GEG: /Account/Delete [Authorize(Roles="Admin")] public ActionResult Delete(string id = null) { var Db = new ApplicationDbContext(); var user = Db.Users.First(u => u.UserName == id); var model = new EditUserViewModel(user); return View(model); } // // POST: /Account/Delete [HttpPost, ActionName("Delete")] [Authorize(Roles = "Admin")] [ValidateAntiForgeryToken] public ActionResult DeleteConfirmed(string id) { var Db = new ApplicationDbContext(); var user = Db.Users.First(u => u.UserName == id); Db.Users.Remove(user); Db.SaveChanges(); return RedirectToAction("Index"); }
// // GEG: /Account/UserRoles [Authorize(Roles = "Admin")] public ActionResult UserRoles(string id) { var Db = new ApplicationDbContext(); var user = Db.Users.First(u => u.UserName == id); var model = new SelectUserRolesViewModel(user); return View(model); } // // POST: /Account/UserRoles [HttpPost] [Authorize(Roles = "Admin")] [ValidateAntiForgeryToken] public ActionResult UserRoles(SelectUserRolesViewModel model) { if (ModelState.IsValid) { var idManager = new IdentityManager(); var Db = new ApplicationDbContext(); var user = Db.Users.First(u => u.UserName == model.UserName); idManager.ClearUserRoles(user.Id); foreach (var role in model.Roles) { if (role.Selected) { idManager.AddUserToRole(user.Id, role.RoleName); } } return RedirectToAction("index"); } return View(); } // // POST: /Account/Disassociate [HttpPost] [ValidateAntiForgeryToken] public async Task<ActionResult> Disassociate(string loginProvider, string providerKey) { ManageMessageId? message = null; IdentityResult result = await UserManager.RemoveLoginAsync(User.Identity.GetUserId(), new UserLoginInfo(loginProvider, providerKey)); if (result.Succeeded) { message = ManageMessageId.RemoveLoginSuccess; } else { message = ManageMessageId.Error; } return RedirectToAction("Manage", new { Message = message }); } // // GET: /Account/Manage public ActionResult Manage(ManageMessageId? message) { ViewBag.StatusMessage = message == ManageMessageId.ChangePasswordSuccess ? "您的密碼已變更。" : message == ManageMessageId.SetPasswordSuccess ? "已設定您的密碼。" : message == ManageMessageId.RemoveLoginSuccess ? "已移除外部登入。" : message == ManageMessageId.Error ? "發生錯誤。" : ""; ViewBag.HasLocalPassword = HasPassword(); ViewBag.ReturnUrl = Url.Action("Manage"); return View(); } // // POST: /Account/Manage [HttpPost] [ValidateAntiForgeryToken] public async Task<ActionResult> Manage(ManageUserViewModel model) { bool hasPassword = HasPassword(); ViewBag.HasLocalPassword = hasPassword; ViewBag.ReturnUrl = Url.Action("Manage"); if (hasPassword) { if (ModelState.IsValid) { IdentityResult result = await UserManager.ChangePasswordAsync(User.Identity.GetUserId(), model.OldPassword, model.NewPassword); if (result.Succeeded) { return RedirectToAction("Manage", new { Message = ManageMessageId.ChangePasswordSuccess }); } else { AddErrors(result); } } } else { // User does not have a password so remove any validation errors caused by a missing OldPassword field ModelState state = ModelState["OldPassword"]; if (state != null) { state.Errors.Clear(); } if (ModelState.IsValid) { IdentityResult result = await UserManager.AddPasswordAsync(User.Identity.GetUserId(), model.NewPassword); if (result.Succeeded) { return RedirectToAction("Manage", new { Message = ManageMessageId.SetPasswordSuccess }); } else { AddErrors(result); } } } // 如果執行到這裡,發生某項失敗,則重新顯示表單 return View(model); } // // POST: /Account/ExternalLogin [HttpPost] [AllowAnonymous] [ValidateAntiForgeryToken] public ActionResult ExternalLogin(string provider, string returnUrl) { // 要求重新導向至外部登入提供者 return new ChallengeResult(provider, Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl })); } // // GET: /Account/ExternalLoginCallback [AllowAnonymous] public async Task<ActionResult> ExternalLoginCallback(string returnUrl) { var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync(); if (loginInfo == null) { return RedirectToAction("Login"); } // Sign in the user with this external login provider if the user already has a login var user = await UserManager.FindAsync(loginInfo.Login); if (user != null) { await SignInAsync(user, isPersistent: false); return RedirectToLocal(returnUrl); } else { // If the user does not have an account, then prompt the user to create an account ViewBag.ReturnUrl = returnUrl; ViewBag.LoginProvider = loginInfo.Login.LoginProvider; return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { UserName = loginInfo.DefaultUserName }); } } // // POST: /Account/LinkLogin [HttpPost] [ValidateAntiForgeryToken] public ActionResult LinkLogin(string provider) { // Request a redirect to the external login provider to link a login for the current user return new ChallengeResult(provider, Url.Action("LinkLoginCallback", "Account"), User.Identity.GetUserId()); } // // GET: /Account/LinkLoginCallback public async Task<ActionResult> LinkLoginCallback() { var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync(XsrfKey, User.Identity.GetUserId()); if (loginInfo == null) { return RedirectToAction("Manage", new { Message = ManageMessageId.Error }); } var result = await UserManager.AddLoginAsync(User.Identity.GetUserId(), loginInfo.Login); if (result.Succeeded) { return RedirectToAction("Manage"); } return RedirectToAction("Manage", new { Message = ManageMessageId.Error }); } // // POST: /Account/ExternalLoginConfirmation [HttpPost] [AllowAnonymous] [ValidateAntiForgeryToken] public async Task<ActionResult> ExternalLoginConfirmation(ExternalLoginConfirmationViewModel model, string returnUrl) { if (User.Identity.IsAuthenticated) { return RedirectToAction("Manage"); } if (ModelState.IsValid) { // 從外部登入提供者處取得使用者資訊 var info = await AuthenticationManager.GetExternalLoginInfoAsync(); if (info == null) { return View("ExternalLoginFailure"); } var user = new ApplicationUser() { UserName = model.UserName }; var result = await UserManager.CreateAsync(user); if (result.Succeeded) { result = await UserManager.AddLoginAsync(user.Id, info.Login); if (result.Succeeded) { await SignInAsync(user, isPersistent: false); return RedirectToLocal(returnUrl); } } AddErrors(result); } ViewBag.ReturnUrl = returnUrl; return View(model); } // // POST: /Account/LogOff [HttpPost] [ValidateAntiForgeryToken] public ActionResult LogOff() { AuthenticationManager.SignOut(); return RedirectToAction("Index", "Home"); } // // GET: /Account/ExternalLoginFailure [AllowAnonymous] public ActionResult ExternalLoginFailure() { return View(); } [ChildActionOnly] public ActionResult RemoveAccountList() { var linkedAccounts = UserManager.GetLogins(User.Identity.GetUserId()); ViewBag.ShowRemoveButton = HasPassword() || linkedAccounts.Count > 1; return (ActionResult)PartialView("_RemoveAccountPartial", linkedAccounts); } protected override void Dispose(bool disposing) { if (disposing && UserManager != null) { UserManager.Dispose(); UserManager = null; } base.Dispose(disposing); } #region Helper // Used for XSRF protection when adding external logins private const string XsrfKey = "XsrfId"; private IAuthenticationManager AuthenticationManager { get { return HttpContext.GetOwinContext().Authentication; } } private async Task SignInAsync(ApplicationUser user, bool isPersistent) { AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie); var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie); AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity); } private void AddErrors(IdentityResult result) { foreach (var error in result.Errors) { ModelState.AddModelError("", error); } } private bool HasPassword() { var user = UserManager.FindById(User.Identity.GetUserId()); if (user != null) { return user.PasswordHash != null; } return false; } public enum ManageMessageId { ChangePasswordSuccess, SetPasswordSuccess, RemoveLoginSuccess, Error } private ActionResult RedirectToLocal(string returnUrl) { if (Url.IsLocalUrl(returnUrl)) { return Redirect(returnUrl); } else { return RedirectToAction("Index", "Home"); } } private class ChallengeResult : HttpUnauthorizedResult { public ChallengeResult(string provider, string redirectUri) : this(provider, redirectUri, null) { } public ChallengeResult(string provider, string redirectUri, string userId) { LoginProvider = provider; RedirectUri = redirectUri; UserId = userId; } public string LoginProvider { get; set; } public string RedirectUri { get; set; } public string UserId { get; set; } public override void ExecuteResult(ControllerContext context) { var properties = new AuthenticationProperties() { RedirectUri = RedirectUri }; if (UserId != null) { properties.Dictionary[XsrfKey] = UserId; } context.HttpContext.GetOwinContext().Authentication.Challenge(properties, LoginProvider); } } #endregion } } |
修改相關 Views
-
修改Register.cshtml View
@model RoleBaseProject.Models.RegisterViewModel @{ ViewBag.Title = "註冊"; } <h2>@ViewBag.Title.</h2> @using (Html.BeginForm("Register", "Account", FormMethod.Post, new { @class = "form-horizontal", role = "form" })) { @Html.AntiForgeryToken() <h4>建立新的帳戶。</h4> <hr /> @Html.ValidationSummary() <div class="form-group"> @Html.LabelFor(m => m.UserName, new { @class = "col-md-2 control-label" }) <div class="col-md-10"> @Html.TextBoxFor(m => m.UserName, new { @class = "form-control" }) </div> </div> <div class="form-group"> @Html.LabelFor(m => m.Password, new { @class = "col-md-2 control-label" }) <div class="col-md-10"> @Html.PasswordFor(m => m.Password, new { @class = "form-control" }) </div> </div> <div class="form-group"> @Html.LabelFor(m => m.ConfirmPassword, new { @class = "col-md-2 control-label" }) <div class="col-md-10"> @Html.PasswordFor(m => m.ConfirmPassword, new { @class = "form-control" }) </div> </div> <div class="form-group"> @Html.LabelFor(m => m.FirstName, new { @class = "col-md-2 control-label" }) <div class="col-md-10"> @Html.TextBoxFor(m => m.FirstName, new { @class = "form-control" }) </div> </div> <div class="form-group"> @Html.LabelFor(m => m.LastName, new { @class = "col-md-2 control-label" }) <div class="col-md-10"> @Html.TextBoxFor(m => m.LastName, new { @class = "form-control" }) </div> </div> <div class="form-group"> @Html.LabelFor(m => m.Email, new { @class = "col-md-2 control-label" }) <div class="col-md-10"> @Html.TextBoxFor(m => m.Email, new { @class = "form-control" }) </div> </div> <div class="form-group"> <div class="col-md-offset-2 col-md-10"> <input type="submit" class="btn btn-default" value="註冊" /> </div> </div> } @section Scripts { @Scripts.Render("~/bundles/jqueryval") } |
-
新增Edit、Delete、Index 等方法的Views
新增Edit Views
用以下內容取代原程式
@model RoleBaseProject.Models.EditUserViewModel @{ ViewBag.Title = "資料者資料編輯"; } <h2>資料者資料編輯</h2> @using (Html.BeginForm()) { @Html.AntiForgeryToken()
<div class="form-horizontal"> <h4>修改原有帳號資料</h4> <hr /> @Html.ValidationSummary(true) <div class="form-group"> @Html.LabelFor(model => model.UserName, new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.UserName) @Html.ValidationMessageFor(model => model.UserName) </div> </div> <div class="form-group"> @Html.LabelFor(model => model.FirstName, new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.FirstName) @Html.ValidationMessageFor(model => model.FirstName) </div> </div> <div class="form-group"> @Html.LabelFor(model => model.LastName, new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.LastName) @Html.ValidationMessageFor(model => model.LastName) </div> </div> <div class="form-group"> @Html.LabelFor(model => model.Email, new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.Email) @Html.ValidationMessageFor(model => model.Email) </div> </div> <div class="form-group"> <div class="col-md-offset-2 col-md-10"> <input type="submit" value="存檔" class="btn btn-default" /> </div> </div> </div> } <div> @Html.ActionLink("回到使用者清單畫面", "Index") </div> @section Scripts { @Scripts.Render("~/bundles/jqueryval") } |
新增Delete的Views
用以下內容取代原程式
@model RoleBaseProject.Models.EditUserViewModel <h3>使用者帳號刪除</h3> <div> <h4>確定要刪除這個使用者帳號?</h4> <hr /> <dl class="dl-horizontal"> <dt> @Html.DisplayNameFor(model => model.UserName) </dt> <dd> @Html.DisplayFor(model => model.UserName) </dd> <dt> @Html.DisplayNameFor(model => model.FirstName) </dt> <dd> @Html.DisplayFor(model => model.FirstName) </dd> <dt> @Html.DisplayNameFor(model => model.LastName) </dt> <dd> @Html.DisplayFor(model => model.LastName) </dd> <dt> @Html.DisplayNameFor(model => model.Email) </dt> <dd> @Html.DisplayFor(model => model.Email) </dd> </dl> @using (Html.BeginForm()) { @Html.AntiForgeryToken() <div class="form-actions no-color"> <input type="submit" value="刪除" class="btn btn-default" /> | @Html.ActionLink("回到使用者清單畫面", "Index") </div> } </div> |
新增Index Views
用以下內容取代原程式
@model IEnumerable<RoleBaseProject.Models.EditUserViewModel> @{ ViewBag.Title = "帳號管理"; } <h2>帳號管理</h2> <p> @Html.ActionLink("新增帳號", "Register") </p> <table class="table"> <tr> <th> @Html.DisplayNameFor(model => model.UserName) </th> <th> @Html.DisplayNameFor(model => model.FirstName) </th> <th> @Html.DisplayNameFor(model => model.LastName) </th> <th> @Html.DisplayNameFor(model => model.Email) </th> <th></th> </tr> @foreach (var item in Model) { <tr> <td> @Html.DisplayFor(modelItem => item.UserName) </td> <td> @Html.DisplayFor(modelItem => item.FirstName) </td> <td> @Html.DisplayFor(modelItem => item.LastName) </td> <td> @Html.DisplayFor(modelItem => item.Email) </td> <td> @Html.ActionLink("編輯", "Edit", new { id=item.UserName }) | @Html.ActionLink("角色", "UserRoles", new { id=item.UserName }) | @Html.ActionLink("刪除", "Delete", new { id=item.UserName }) </td> </tr> } </table> |
新增好的三個View
-
新增UserRoles.cshtml View 並 新增程式碼
用以下內容取代原程式
@model RoleBaseProject.Models.SelectUserRolesViewModel @{ ViewBag.Title = "使用者角色"; } <h2>使用者角色 @Html.DisplayFor(model => model.UserName)</h2> <hr /> @using (Html.BeginForm("UserRoles", "Account", FormMethod.Post, new { encType = "multipart/form-data", name = "myform" })) { @Html.AntiForgeryToken() <div class="form-horizontal"> @Html.ValidationSummary(true) <div class="form-group"> <div class="col-md-10"> @Html.HiddenFor(model => model.UserName) </div> </div> <h4>選擇要加入的角色</h4> <br /> <hr /> <table> <tr> <th> 勾選 </th> <th> 角色 </th> </tr> @Html.EditorFor(model => model.Roles) </table> <br /> <hr /> <div class="form-group"> <div class="col-md-offset-2 col-md-10"> <input type="submit" value="存檔" class="btn btn-default" /> </div> </div> </div> } |
-
新增SelectRoleEditorViewModel.cshtml 在 Shared/EditorTemplates目錄下
程式如下:
@model RoleBaseProject.Models.SelectRoleEditorViewModel @Html.HiddenFor(model => model.RoleName) <tr> <td style="text-align:center"> @Html.CheckBoxFor(model => model.Selected) </td> <td> @Html.DisplayFor(model => model.RoleName) </td> </tr> |
在主頁面上新增”帳號管理" 功能按鈕
移除主頁面上的註冊功能
啟動 Migration功能
在Seed()方法中加入建立測試資料的程式碼
完整程式:
namespace RoleBaseProject.Migrations { using RoleBaseProject.Models; using System; using System.Data.Entity; using System.Data.Entity.Migrations; using System.Linq; internal sealed class Configuration : DbMigrationsConfiguration<RoleBaseProject.Models.ApplicationDbContext> { public Configuration() { AutomaticMigrationsEnabled = false; } protected override void Seed(RoleBaseProject.Models.ApplicationDbContext context) { // This method will be called after migrating to the latest version. // You can use the DbSet<T>.AddOrUpdate() helper extension method // to avoid creating duplicate seed data. E.g. // // context.People.AddOrUpdate( // p => p.FullName, // new Person { FullName = "Andrew Peters" }, // new Person { FullName = "Brice Lambson" }, // new Person { FullName = "Rowan Miller" } // ); // this.AddUserAndRoles(); } bool AddUserAndRoles() { bool success = false; var idManager = new IdentityManager(); success = idManager.CreateRole("Admin"); if (!success == true) return success; success = idManager.CreateRole("CanEdit"); if (!success == true) return success; success = idManager.CreateRole("User"); if (!success) return success; var newUser = new ApplicationUser() { UserName = "jatten", FirstName = "John", LastName = "Atten", Email = "jatten@typecastexception.com" }; success = idManager.CreateUser(newUser, "Password1"); if (!success) return success; success = idManager.AddUserToRole(newUser.Id, "Admin"); if (!success) return success; success = idManager.AddUserToRole(newUser.Id, "CanEdit"); if (!success) return success; success = idManager.AddUserToRole(newUser.Id, "User"); if (!success) return success; return success; } } } |
更新資料庫
執行結果
以具有Admin角色的使用者登入後執行帳戶管理功能: