在ASP.NET MVC5中建置以角色為基礎的授權機制

摘要:在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角色的使用者登入後執行帳戶管理功能: