• 在ASP.NET MVC5中建置以角色为基础的授权机制


    在前一篇贴文中,已探索过如何在MVC5中自定ASP.NET Identity,接下来要来试试在MVC5中如何运用 ASP.NET Identity来设定一个以 "角色"为基础的授权机制。为了方便起见,简化了这个认证机制的内容,同时假设这是一个公司内部使用的应用程序,所以拿掉了"注册"的功能,所有的使用账 号管理都必须透过某一管理权限(Admin)的使用者来进行,也就是说只有具备有 Admin 角色的使用者可以执行”账户管理"的功能。
    贴文内容:
    建立MVC5新项目
    修改相关 Mdels
    扩展Identity Management Mdel 
    加入新字段
    建立Helper Class
    扩展Accunt Management ViewMdels (AccuntViewMdels.cs)
    在RegisterViewMdel加入新字段 及 GetUser methd
    新增 EditUserViewMdel、SelectUserRlesViewMdel、SelectRleEditrViewMdel
    修改相关 Cntrllers
    修改AccuntCntrller 中 Register Methd 加入 Authrize attribute
    加入 Index Methd (ActinResult)
    加入 Edit Methd (ActinResult)
    加入 Delete Methd (ActinResult)
    加入 UserRles Methd (ActinResult)
    修改相关 Views
    修改Register.cshtml View 
    新增Edit、Delete、Index 等方法的Views
    新增UserRles.cshtml View 并 新增程序代码
    新增 SelectRleEditrViewMdel.cshtml 在 Shared/EditrTemplates目录下
    在主页面上新增”账号管理" 功能按钮
    移除主页面上的注册功能
    启动 Migratin功能
    在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 完整程序

    01.using Microsoft.AspNet.Identity;
    02.using Microsoft.AspNet.Identity.EntityFramework;
    03.using System.Collections.Generic;
    04.using System.ComponentModel.DataAnnotations;
    05. 
    06.namespace RoleBaseProject.Models
    07.{
    08.// 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.
    09.public class ApplicationUser : IdentityUser
    10.{
    11.[Required]
    12.public string FirstName { get; set; }
    13. 
    14.[Required]
    15.public string LastName { get; set; }
    16.[Required]
    17.public string Email { get; set; }
    18.}
    19. 
    20.public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
    21.{
    22.public ApplicationDbContext()
    23.: base("DefaultConnection")
    24.{
    25.}
    26.}
    27. 
    28.public class IdentityManager
    29.{
    30.// 判断角色是否已在存在
    31.public bool RoleExists(string name)
    32.{
    33.var rm = new RoleManager<IdentityRole>(
    34.new RoleStore<IdentityRole>(new ApplicationDbContext()));
    35.return rm.RoleExists(name);
    36.}
    37.// 新增角色
    38.public bool CreateRole(string name)
    39.{
    40.var rm = new RoleManager<IdentityRole>(
    41.new RoleStore<IdentityRole>(new ApplicationDbContext()));
    42.var idResult = rm.Create(new IdentityRole(name));
    43.return idResult.Succeeded;
    44.}
    45.// 新增角色
    46.public bool CreateUser(ApplicationUser user, string pass<a href="http://www.it165.net/edu/ebg/" target="_blank" class="keylink">word</a>)
    47.{
    48.var um = new UserManager<ApplicationUser>(
    49.new UserStore<ApplicationUser>(new ApplicationDbContext()));
    50.var idResult = um.Create(user, pass<a href="http://www.it165.net/edu/ebg/" target="_blank" class="keylink">word</a>);
    51.return idResult.Succeeded;
    52.}
    53.// 将使用者加入角色中
    54.public bool AddUserToRole(string userId, string roleName)
    55.{
    56.var um = new UserManager<ApplicationUser>(
    57.new UserStore<ApplicationUser>(new ApplicationDbContext()));
    58.var idResult = um.AddToRole(userId, roleName);
    59.return idResult.Succeeded;
    60.}
    61.// 清除使用者的角色设定
    62.public void ClearUserRoles(string userId)
    63.{
    64.var um = new UserManager<ApplicationUser>(
    65.new UserStore<ApplicationUser>(new ApplicationDbContext()));
    66.var user = um.FindById(userId);
    67.var currentRoles = new List<IdentityUserRole>();
    68.currentRoles.AddRange(user.Roles);
    69.foreach(var role in currentRoles)
    70.{
    71.um.RemoveFromRole(userId, role.Role.Name);
    72.}
    73.}
    74.}
    75.}
    2. 扩展Account Management ViewModels (AccountViewModels.cs)
     
    在RegisterViewModel加入新字段 及 GetUser method
     

     
     
    针对要新增的"账号管理"功能新增三个ViewModel,分别是: EditUserViewModel、SelectUserRolesViewModel、SelectRoleEditorViewModel
     
    AccountViewModels.cs 完整程序


    001.using Microsoft.AspNet.Identity.EntityFramework;
    002.using System.Collections.Generic;
    003.using System.ComponentModel.DataAnnotations;
    004. 
    005.namespace RoleBaseProject.Models
    006.{
    007.public class ExternalLoginConfirmationViewModel
    008.{
    009.[Required]
    010.[Display(Name = "使用者名称")]
    011.public string UserName { get; set; }
    012.}
    013. 
    014.public class ManageUserViewModel
    015.{
    016.[Required]
    017.[DataType(DataType.Password)]
    018.[Display(Name = "目前密码")]
    019.public string OldPassword { get; set; }
    020. 
    021.[Required]
    022.[StringLength(100, ErrorMessage = "{0} 的长度至少必须为 {2} 个字符。", MinimumLength = 6)]
    023.[DataType(DataType.Password)]
    024.[Display(Name = "新密码")]
    025.public string NewPassword { get; set; }
    026. 
    027.[DataType(DataType.Password)]
    028.[Display(Name = "确认新密码")]
    029.[Compare("NewPassword", ErrorMessage = "新密码与确认密码不相符。")]
    030.public string ConfirmPassword { get; set; }
    031.}
    032. 
    033.public class LoginViewModel
    034.{
    035.[Required]
    036.[Display(Name = "使用者名称")]
    037.public string UserName { get; set; }
    038. 
    039.[Required]
    040.[DataType(DataType.Password)]
    041.[Display(Name = "密码")]
    042.public string Password { get; set; }
    043. 
    044.[Display(Name = "记住我?")]
    045.public bool RememberMe { get; set; }
    046.}
    047. 
    048.public class RegisterViewModel
    049.{
    050.[Required]
    051.[Display(Name = "使用者名称")]
    052.public string UserName { get; set; }
    053. 
    054.[Required]
    055.[StringLength(100, ErrorMessage = "{0} 的长度至少必须为 {2} 个字符。", MinimumLength = 6)]
    056.[DataType(DataType.Password)]
    057.[Display(Name = "密码")]
    058.public string Password { get; set; }
    059. 
    060.[DataType(DataType.Password)]
    061.[Display(Name = "确认密码")]
    062.[Compare("Password", ErrorMessage = "密码和确认密码不相符。")]
    063.public string ConfirmPassword { get; set; }
    064. 
    065.[Required]
    066.[Display(Name = "First Name")]
    067.public string FirstName { get; set; }
    068. 
    069.[Required]
    070.[Display(Name = "Last Name")]
    071.public string LastName { get; set; }
    072. 
    073.[Required]
    074.[Display(Name = "电子邮件信箱")]
    075.public string Email { get; set; }
    076. 
    077.public ApplicationUser GetUser()
    078.{
    079.var user = new ApplicationUser()
    080.{
    081.UserName = this.UserName,
    082.FirstName = this.FirstName,
    083.LastName = this.LastName,
    084.Email = this.Email,
    085.};
    086.return user;
    087.}
    088.}
    089. 
    090.public class EditUserViewModel
    091.{
    092.public EditUserViewModel() { }
    093. 
    094.// Allow Initialization with an instance of ApplicationUser:
    095.public EditUserViewModel(ApplicationUser user)
    096.{
    097.this.UserName = user.UserName;
    098.this.FirstName = user.FirstName;
    099.this.LastName = user.LastName;
    100.this.Email = user.Email;
    101.}
    102. 
    103.[Required]
    104.[Display(Name = "使用者账号")]
    105.public string UserName { get; set; }
    106. 
    107.[Required]
    108.[Display(Name = "名")]
    109.public string FirstName { get; set; }
    110. 
    111.[Required]
    112.[Display(Name = "姓")]
    113.public string LastName { get; set; }
    114. 
    115.[Required]
    116.[Display(Name = "电子邮件信箱")]
    117.public string Email { get; set; }
    118.}
    119. 
    120.public class SelectUserRolesViewModel
    121.{
    122.public SelectUserRolesViewModel()
    123.{
    124.this.Roles = new List<SelectRoleEditorViewModel>();
    125.}
    126. 
    127.// Enable initialization with an instance of ApplicationUser:
    128.public SelectUserRolesViewModel(ApplicationUser user)
    129.: this()
    130.{
    131.this.UserName = user.UserName;
    132.this.FirstName = user.FirstName;
    133.this.LastName = user.LastName;
    134. 
    135.var Db = new ApplicationDbContext();
    136. 
    137.// Add all available roles to the list of EditorViewModels:
    138.var allRoles = Db.Roles;
    139.foreach (var role in allRoles)
    140.{
    141.// An EditorViewModel will be used by Editor Template:
    142.var rvm = new SelectRoleEditorViewModel(role);
    143.this.Roles.Add(rvm);
    144.}
    145. 
    146.// Set the Selected property to true for those roles for
    147.// which the current user is a member:
    148.foreach (var userRole in user.Roles)
    149.{
    150.var checkUserRole =
    151.this.Roles.Find(r => r.RoleName == userRole.Role.Name);
    152.checkUserRole.Selected = true;
    153.}
    154.}
    155. 
    156.public string UserName { get; set; }
    157.public string FirstName { get; set; }
    158.public string LastName { get; set; }
    159.public List<SelectRoleEditorViewModel> Roles { get; set; }
    160.}
    161. 
    162.// Used to display a single role with a checkbox, within a list structure:
    163.public class SelectRoleEditorViewModel
    164.{
    165.public SelectRoleEditorViewModel() { }
    166.public SelectRoleEditorViewModel(IdentityRole role)
    167.{
    168.this.RoleName = role.Name;
    169.}
    170. 
    171.public bool Selected { get; set; }
    172. 
    173.[Required]
    174.public string RoleName { get; set; }
    175.}
    176. 
    177.}
    修改相关 Controllers
     
    修改AccountController 中 Register Method 加入 Authorize attribute
     

     
     

    必须具有Admin 角色者才能执行。

     
    加入 Index Method (ActionResult)


    01.[Authorize(Roles = "Admin")]
    02.public ActionResult Index()
    03.{
    04.var Db = new ApplicationDbContext();
    05.var users = Db.Users;
    06.var model = new List<EditUserViewModel>();
    07.foreach(var user in users)
    08.{
    09.var u = new EditUserViewModel(user);
    10.model.Add(u);
    11.}
    12.return View(model);
    13.}

    加入 Edit Method (ActionResult)


     

    01.//
    02.// GEG: /Account/Edit
    03.[Authorize(Roles = "Admin")]
    04.public ActionResult Edit(string id , ManageMessageId? Message = null)
    05.{
    06.var Db = new ApplicationDbContext();
    07.var user = Db.Users.First(u => u.UserName == id);
    08.var model = new EditUserViewModel(user);
    09.ViewBag.MessageId = Message;
    10.return View(model);
    11.}
    12.//
    13.// POST: /Account/Edit
    14.[HttpPost]
    15.[Authorize(Roles = "Admin")]
    16.[ValidateAntiForgeryToken]
    17.public async Task<ActionResult> Edit(EditUserViewModel model)
    18.{
    19.if (ModelState.IsValid)
    20.{
    21.var Db = new ApplicationDbContext();
    22.var user = Db.Users.First(u => u.UserName == model.UserName);
    23.user.FirstName = model.FirstName;
    24.user.LastName = model.LastName;
    25.user.Email = model.Email;
    26.Db.Entry(user).State = System.Data.Entity.EntityState.Modified;
    27.await Db.SaveChangesAsync();
    28.return RedirectToAction("Index");
    29.}
    30.return View(model);
    31.}


    加入 Delete Method (ActionResult)


     

    01.//
    02.// GEG: /Account/Delete
    03.[Authorize(Roles="Admin")]
    04.public ActionResult Delete(string id = null)
    05.{
    06.var Db = new ApplicationDbContext();
    07.var user = Db.Users.First(u => u.UserName == id);
    08.var model = new EditUserViewModel(user);
    09.return View(model);
    10.}
    11.//
    12.// POST: /Account/Delete
    13.[HttpPost, ActionName("Delete")]
    14.[Authorize(Roles = "Admin")]
    15.[ValidateAntiForgeryToken]
    16.public ActionResult DeleteConfirmed(string id)
    17.{
    18.var Db = new ApplicationDbContext();
    19.var user = Db.Users.First(u => u.UserName == id);
    20.Db.Users.Remove(user);
    21.Db.SaveChanges();
    22.return RedirectToAction("Index");
    23.}

    加入 UserRoles Method (ActionResult)
     

    01.//
    02.// GEG: /Account/UserRoles
    03.[Authorize(Roles = "Admin")]
    04.public ActionResult UserRoles(string id)
    05.{
    06.var Db = new ApplicationDbContext();
    07.var user = Db.Users.First(u => u.UserName == id);
    08.var model = new SelectUserRolesViewModel(user);
    09.return View(model);
    10.}
    11. 
    12.//
    13.// POST: /Account/UserRoles
    14.[HttpPost]
    15.[Authorize(Roles = "Admin")]
    16.[ValidateAntiForgeryToken]
    17.public ActionResult UserRoles(SelectUserRolesViewModel model)
    18.{
    19.if (ModelState.IsValid)
    20.{
    21.var idManager = new IdentityManager();
    22.var Db = new ApplicationDbContext();
    23.var user = Db.Users.First(u => u.UserName == model.UserName);
    24.idManager.ClearUserRoles(user.Id);
    25.foreach (var role in model.Roles)
    26.{
    27.if (role.Selected)
    28.{
    29.idManager.AddUserToRole(user.Id, role.RoleName);
    30.}
    31.}
    32.return RedirectToAction("index");
    33.}
    34.return View();
    35.}

    AccountController.cs 完整程序


     

    001.using System;
    002.using System.Collections.Generic;
    003.using System.Linq;
    004.using System.Security.Claims;
    005.using System.Threading.Tasks;
    006.using System.Web;
    007.using System.Web.Mvc;
    008.using Microsoft.AspNet.Identity;
    009.using Microsoft.AspNet.Identity.EntityFramework;
    010.using Microsoft.Owin.Security;
    011.using RoleBaseProject.Models;
    012. 
    013.namespace RoleBaseProject.Controllers
    014.{
    015.[Authorize]
    016.public class AccountController : Controller
    017.{
    018.public AccountController()
    019.: this(new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext())))
    020.{
    021.}
    022. 
    023.public AccountController(UserManager<ApplicationUser> userManager)
    024.{
    025.UserManager = userManager;
    026.}
    027. 
    028.public UserManager<ApplicationUser> UserManager { get; private set; }
    029. 
    030.//
    031.// GET: /Account/Login
    032.[AllowAnonymous]
    033.public ActionResult Login(string returnUrl)
    034.{
    035.ViewBag.ReturnUrl = returnUrl;
    036.return View();
    037.}
    038. 
    039.//
    040.// POST: /Account/Login
    041.[HttpPost]
    042.[AllowAnonymous]
    043.[ValidateAntiForgeryToken]
    044.public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
    045.{
    046.if (ModelState.IsValid)
    047.{
    048.var user = await UserManager.FindAsync(model.UserName, model.Password);
    049.if (user != null)
    050.{
    051.await SignInAsync(user, model.RememberMe);
    052.return RedirectToLocal(returnUrl);
    053.}
    054.else
    055.{
    056.ModelState.AddModelError("", "Invalid username or password.");
    057.}
    058.}
    059. 
    060.// 如果执行到这里,发生某项失败,则重新显示窗体
    061.return View(model);
    062.}
    063. 
    064.//
    065.// GET: /Account/Register
    066.[Authorize(Roles="Admin")]
    067.public ActionResult Register()
    068.{
    069.return View();
    070.}
    071. 
    072.//
    073.// POST: /Account/Register
    074.[HttpPost]
    075.[Authorize(Roles = "Admin")]
    076.[ValidateAntiForgeryToken]
    077.public async Task<ActionResult> Register(RegisterViewModel model)
    078.{
    079.if (ModelState.IsValid)
    080.{
    081.var user = new ApplicationUser() {
    082.UserName = model.UserName,
    083.FirstName = model.FirstName,
    084.LastName = model.LastName,
    085.Email = model.Email,
    086.};
    087.var result = await UserManager.CreateAsync(user, model.Password);
    088.if (result.Succeeded)
    089.{
    090.await SignInAsync(user, isPersistent: false);
    091.return RedirectToAction("Index", "Home");
    092.}
    093.else
    094.{
    095.AddErrors(result);
    096.}
    097.}
    098. 
    099.// 如果执行到这里,发生某项失败,则重新显示窗体
    100.return View(model);
    101.}
    102. 
    103.//
    104.// GEG: /Account/Index
    105.[Authorize(Roles = "Admin")]
    106.public ActionResult Index()
    107.{
    108.var Db = new ApplicationDbContext();
    109.var users = Db.Users;
    110.var model = new List<EditUserViewModel>();
    111.foreach(var user in users)
    112.{
    113.var u = new EditUserViewModel(user);
    114.model.Add(u);
    115.}
    116.return View(model);
    117.}
    118. 
    119.//
    120.// GEG: /Account/Edit
    121.[Authorize(Roles = "Admin")]
    122.public ActionResult Edit(string id , ManageMessageId? Message = null)
    123.{
    124.var Db = new ApplicationDbContext();
    125.var user = Db.Users.First(u => u.UserName == id);
    126.var model = new EditUserViewModel(user);
    127.ViewBag.MessageId = Message;
    128.return View(model);
    129.}
    130.//
    131.// POST: /Account/Edit
    132.[HttpPost]
    133.[Authorize(Roles = "Admin")]
    134.[ValidateAntiForgeryToken]
    135.public async Task<ActionResult> Edit(EditUserViewModel model)
    136.{
    137.if (ModelState.IsValid)
    138.{
    139.var Db = new ApplicationDbContext();
    140.var user = Db.Users.First(u => u.UserName == model.UserName);
    141.user.FirstName = model.FirstName;
    142.user.LastName = model.LastName;
    143.user.Email = model.Email;
    144.Db.Entry(user).State = System.Data.Entity.EntityState.Modified;
    145.await Db.SaveChangesAsync();
    146.return RedirectToAction("Index");
    147.}
    148.return View(model);
    149.}
    150. 
    151.//
    152.// GEG: /Account/Delete
    153.[Authorize(Roles="Admin")]
    154.public ActionResult Delete(string id = null)
    155.{
    156.var Db = new ApplicationDbContext();
    157.var user = Db.Users.First(u => u.UserName == id);
    158.var model = new EditUserViewModel(user);
    159.return View(model);
    160.}
    161.//
    162.// POST: /Account/Delete
    163.[HttpPost, ActionName("Delete")]
    164.[Authorize(Roles = "Admin")]
    165.[ValidateAntiForgeryToken]
    166.public ActionResult DeleteConfirmed(string id)
    167.{
    168.var Db = new ApplicationDbContext();
    169.var user = Db.Users.First(u => u.UserName == id);
    170.Db.Users.Remove(user);
    171.Db.SaveChanges();
    172.return RedirectToAction("Index");
    173.}
    174.//
    175.// GEG: /Account/UserRoles
    176.[Authorize(Roles = "Admin")]
    177.public ActionResult UserRoles(string id)
    178.{
    179.var Db = new ApplicationDbContext();
    180.var user = Db.Users.First(u => u.UserName == id);
    181.var model = new SelectUserRolesViewModel(user);
    182.return View(model);
    183.}
    184. 
    185.//
    186.// POST: /Account/UserRoles
    187.[HttpPost]
    188.[Authorize(Roles = "Admin")]
    189.[ValidateAntiForgeryToken]
    190.public ActionResult UserRoles(SelectUserRolesViewModel model)
    191.{
    192.if (ModelState.IsValid)
    193.{
    194.var idManager = new IdentityManager();
    195.var Db = new ApplicationDbContext();
    196.var user = Db.Users.First(u => u.UserName == model.UserName);
    197.idManager.ClearUserRoles(user.Id);
    198.foreach (var role in model.Roles)
    199.{
    200.if (role.Selected)
    201.{
    202.idManager.AddUserToRole(user.Id, role.RoleName);
    203.}
    204.}
    205.return RedirectToAction("index");
    206.}
    207.return View();
    208.}
    209. 
    210.//
    211.// POST: /Account/Disassociate
    212.[HttpPost]
    213.[ValidateAntiForgeryToken]
    214.public async Task<ActionResult> Disassociate(string loginProvider, string providerKey)
    215.{
    216.ManageMessageId? message = null;
    217.IdentityResult result = await UserManager.RemoveLoginAsync(User.Identity.GetUserId(), new UserLoginInfo(loginProvider, providerKey));
    218.if (result.Succeeded)
    219.{
    220.message = ManageMessageId.RemoveLoginSuccess;
    221.}
    222.else
    223.{
    224.message = ManageMessageId.Error;
    225.}
    226.return RedirectToAction("Manage", new { Message = message });
    227.}
    228. 
    229.//
    230.// GET: /Account/Manage
    231.public ActionResult Manage(ManageMessageId? message)
    232.{
    233.ViewBag.StatusMessage =
    234.message == ManageMessageId.ChangePasswordSuccess ? "您的密码已变更。"
    235.: message == ManageMessageId.SetPasswordSuccess ? "已设定您的密码。"
    236.: message == ManageMessageId.RemoveLoginSuccess ? "已移除外部登入。"
    237.: message == ManageMessageId.Error ? "发生错误。"
    238.: "";
    239.ViewBag.HasLocalPassword = HasPassword();
    240.ViewBag.ReturnUrl = Url.Action("Manage");
    241.return View();
    242.}
    243. 
    244.//
    245.// POST: /Account/Manage
    246.[HttpPost]
    247.[ValidateAntiForgeryToken]
    248.public async Task<ActionResult> Manage(ManageUserViewModel model)
    249.{
    250.bool hasPassword = HasPassword();
    251.ViewBag.HasLocalPassword = hasPassword;
    252.ViewBag.ReturnUrl = Url.Action("Manage");
    253.if (hasPassword)
    254.{
    255.if (ModelState.IsValid)
    256.{
    257.IdentityResult result = await UserManager.ChangePasswordAsync(User.Identity.GetUserId(), model.OldPassword, model.NewPassword);
    258.if (result.Succeeded)
    259.{
    260.return RedirectToAction("Manage", new { Message = ManageMessageId.ChangePasswordSuccess });
    261.}
    262.else
    263.{
    264.AddErrors(result);
    265.}
    266.}
    267.}
    268.else
    269.{
    270.// User does not have a password so remove any validation errors caused by a missing OldPassword field
    271.ModelState state = ModelState["OldPassword"];
    272.if (state != null)
    273.{
    274.state.Errors.Clear();
    275.}
    276. 
    277.if (ModelState.IsValid)
    278.{
    279.IdentityResult result = await UserManager.AddPasswordAsync(User.Identity.GetUserId(), model.NewPassword);
    280.if (result.Succeeded)
    281.{
    282.return RedirectToAction("Manage", new { Message = ManageMessageId.SetPasswordSuccess });
    283.}
    284.else
    285.{
    286.AddErrors(result);
    287.}
    288.}
    289.}
    290. 
    291.// 如果执行到这里,发生某项失败,则重新显示窗体
    292.return View(model);
    293.}
    294. 
    295.//
    296.// POST: /Account/ExternalLogin
    297.[HttpPost]
    298.[AllowAnonymous]
    299.[ValidateAntiForgeryToken]
    300.public ActionResult ExternalLogin(string provider, string returnUrl)
    301.{
    302.// 要求重新导向至外部登入提供者
    303.return new ChallengeResult(provider, Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl }));
    304.}
    305. 
    306.//
    307.// GET: /Account/ExternalLoginCallback
    308.[AllowAnonymous]
    309.public async Task<ActionResult> ExternalLoginCallback(string returnUrl)
    310.{
    311.var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();
    312.if (loginInfo == null)
    313.{
    314.return RedirectToAction("Login");
    315.}
    316. 
    317.// Sign in the user with this external login provider if the user already has a login
    318.var user = await UserManager.FindAsync(loginInfo.Login);
    319.if (user != null)
    320.{
    321.await SignInAsync(user, isPersistent: false);
    322.return RedirectToLocal(returnUrl);
    323.}
    324.else
    325.{
    326.// If the user does not have an account, then prompt the user to create an account
    327.ViewBag.ReturnUrl = returnUrl;
    328.ViewBag.LoginProvider = loginInfo.Login.LoginProvider;
    329.return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { UserName = loginInfo.DefaultUserName });
    330.}
    331.}
    332. 
    333.//
    334.// POST: /Account/LinkLogin
    335.[HttpPost]
    336.[ValidateAntiForgeryToken]
    337.public ActionResult LinkLogin(string provider)
    338.{
    339.// Request a redirect to the external login provider to link a login for the current user
    340.return new ChallengeResult(provider, Url.Action("LinkLoginCallback", "Account"), User.Identity.GetUserId());
    341.}
    342. 
    343.//
    344.// GET: /Account/LinkLoginCallback
    345.public async Task<ActionResult> LinkLoginCallback()
    346.{
    347.var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync(XsrfKey, User.Identity.GetUserId());
    348.if (loginInfo == null)
    349.{
    350.return RedirectToAction("Manage", new { Message = ManageMessageId.Error });
    351.}
    352.var result = await UserManager.AddLoginAsync(User.Identity.GetUserId(), loginInfo.Login);
    353.if (result.Succeeded)
    354.{
    355.return RedirectToAction("Manage");
    356.}
    357.return RedirectToAction("Manage", new { Message = ManageMessageId.Error });
    358.}
    359. 
    360.//
    361.// POST: /Account/ExternalLoginConfirmation
    362.[HttpPost]
    363.[AllowAnonymous]
    364.[ValidateAntiForgeryToken]
    365.public async Task<ActionResult> ExternalLoginConfirmation(ExternalLoginConfirmationViewModel model, string returnUrl)
    366.{
    367.if (User.Identity.IsAuthenticated)
    368.{
    369.return RedirectToAction("Manage");
    370.}
    371. 
    372.if (ModelState.IsValid)
    373.{
    374.// 从外部登入提供者处取得使用者信息
    375.var info = await AuthenticationManager.GetExternalLoginInfoAsync();
    376.if (info == null)
    377.{
    378.return View("ExternalLoginFailure");
    379.}
    380.var user = new ApplicationUser() { UserName = model.UserName };
    381.var result = await UserManager.CreateAsync(user);
    382.if (result.Succeeded)
    383.{
    384.result = await UserManager.AddLoginAsync(user.Id, info.Login);
    385.if (result.Succeeded)
    386.{
    387.await SignInAsync(user, isPersistent: false);
    388.return RedirectToLocal(returnUrl);
    389.}
    390.}
    391.AddErrors(result);
    392.}
    393. 
    394.ViewBag.ReturnUrl = returnUrl;
    395.return View(model);
    396.}
    397. 
    398.//
    399.// POST: /Account/LogOff
    400.[HttpPost]
    401.[ValidateAntiForgeryToken]
    402.public ActionResult LogOff()
    403.{
    404.AuthenticationManager.SignOut();
    405.return RedirectToAction("Index", "Home");
    406.}
    407. 
    408.//
    409.// GET: /Account/ExternalLoginFailure
    410.[AllowAnonymous]
    411.public ActionResult ExternalLoginFailure()
    412.{
    413.return View();
    414.}
    415. 
    416.[ChildActionOnly]
    417.public ActionResult RemoveAccountList()
    418.{
    419.var linkedAccounts = UserManager.GetLogins(User.Identity.GetUserId());
    420.ViewBag.ShowRemoveButton = HasPassword() || linkedAccounts.Count > 1;
    421.return (ActionResult)PartialView("_RemoveAccountPartial", linkedAccounts);
    422.}
    423. 
    424.protected override void Dispose(bool disposing)
    425.{
    426.if (disposing && UserManager != null)
    427.{
    428.UserManager.Dispose();
    429.UserManager = null;
    430.}
    431.base.Dispose(disposing);
    432.}
    433. 
    434.#region Helper
    435.// Used for XSRF protection when adding external logins
    436.private const string XsrfKey = "XsrfId";
    437. 
    438.private IAuthenticationManager AuthenticationManager
    439.{
    440.get
    441.{
    442.return HttpContext.GetOwinContext().Authentication;
    443.}
    444.}
    445. 
    446.private async Task SignInAsync(ApplicationUser user, bool isPersistent)
    447.{
    448.AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
    449.var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
    450.AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity);
    451.}
    452. 
    453.private void AddErrors(IdentityResult result)
    454.{
    455.foreach (var error in result.Errors)
    456.{
    457.ModelState.AddModelError("", error);
    458.}
    459.}
    460. 
    461.private bool HasPassword()
    462.{
    463.var user = UserManager.FindById(User.Identity.GetUserId());
    464.if (user != null)
    465.{
    466.return user.PasswordHash != null;
    467.}
    468.return false;
    469.}
    470. 
    471.public enum ManageMessageId
    472.{
    473.ChangePasswordSuccess,
    474.SetPasswordSuccess,
    475.RemoveLoginSuccess,
    476.Error
    477.}
    478. 
    479.private ActionResult RedirectToLocal(string returnUrl)
    480.{
    481.if (Url.IsLocalUrl(returnUrl))
    482.{
    483.return Redirect(returnUrl);
    484.}
    485.else
    486.{
    487.return RedirectToAction("Index", "Home");
    488.}
    489.}
    490. 
    491.private class ChallengeResult : HttpUnauthorizedResult
    492.{
    493.public ChallengeResult(string provider, string redirectUri) : this(provider, redirectUri, null)
    494.{
    495.}
    496. 
    497.public ChallengeResult(string provider, string redirectUri, string userId)
    498.{
    499.LoginProvider = provider;
    500.RedirectUri = redirectUri;
    501.UserId = userId;
    502.}
    503. 
    504.public string LoginProvider { get; set; }
    505.public string RedirectUri { get; set; }
    506.public string UserId { get; set; }
    507. 
    508.public override void ExecuteResult(ControllerContext context)
    509.{
    510.var properties = new AuthenticationProperties() { RedirectUri = RedirectUri };
    511.if (UserId != null)
    512.{
    513.properties.Dictionary[XsrfKey] = UserId;
    514.}
    515.context.HttpContext.GetOwinContext().Authentication.Challenge(properties, LoginProvider);
    516.}
    517.}
    518.#endregion
    519.}
    520.}


     

    修改相关 Views
     
    修改Register.cshtml View 


    01.@model RoleBaseProject.Models.RegisterViewModel
    02.@{
    03.ViewBag.Title = "注册";
    04.}
    05. 
    06.<h2>@ViewBag.Title.</h2>
    07. 
    08.@using (Html.BeginForm("Register", "Account", FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
    09.{
    10.@Html.AntiForgeryToken()
    11.<h4>建立新的账户。</h4>
    12.<hr />
    13.@Html.ValidationSummary()
    14.<div class="form-group">
    15.@Html.LabelFor(m => m.UserName, new { @class = "col-md-2 control-label" })
    16.<div class="col-md-10">
    17.@Html.TextBoxFor(m => m.UserName, new { @class = "form-control" })
    18.</div>
    19.</div>
    20.<div class="form-group">
    21.@Html.LabelFor(m => m.Password, new { @class = "col-md-2 control-label" })
    22.<div class="col-md-10">
    23.@Html.PasswordFor(m => m.Password, new { @class = "form-control" })
    24.</div>
    25.</div>
    26.<div class="form-group">
    27.@Html.LabelFor(m => m.ConfirmPassword, new { @class = "col-md-2 control-label" })
    28.<div class="col-md-10">
    29.@Html.PasswordFor(m => m.ConfirmPassword, new { @class = "form-control" })
    30.</div>
    31.</div>
    32.<div class="form-group">
    33.@Html.LabelFor(m => m.FirstName, new { @class = "col-md-2 control-label" })
    34.<div class="col-md-10">
    35.@Html.TextBoxFor(m => m.FirstName, new { @class = "form-control" })
    36.</div>
    37.</div>
    38.<div class="form-group">
    39.@Html.LabelFor(m => m.LastName, new { @class = "col-md-2 control-label" })
    40.<div class="col-md-10">
    41.@Html.TextBoxFor(m => m.LastName, new { @class = "form-control" })
    42.</div>
    43.</div>
    44.<div class="form-group">
    45.@Html.LabelFor(m => m.Email, new { @class = "col-md-2 control-label" })
    46.<div class="col-md-10">
    47.@Html.TextBoxFor(m => m.Email, new { @class = "form-control" })
    48.</div>
    49.</div>
    50.<div class="form-group">
    51.<div class="col-md-offset-2 col-md-10">
    52.<input type="submit" class="btn btn-default" value="注册" />
    53.</div>
    54.</div>
    55.}
    56. 
    57.@section Scripts {
    58.@Scripts.Render("~/bundles/jqueryval")
    59.}
     
    新增Edit、Delete、Index 等方法的Views
     
    新增Edit Views
     




     
    用以下内容取代原程序


    01.@model RoleBaseProject.Models.EditUserViewModel
    02. 
    03.@{
    04.ViewBag.Title = "数据者数据编辑";
    05.}
    06. 
    07.<h2>数据者数据编辑</h2>
    08. 
    09.@using (Html.BeginForm())
    10.{
    11.@Html.AntiForgeryToken()
    12.<div class="form-horizontal">
    13.<h4>修改原有账号数据</h4>
    14.<hr />
    15.@Html.ValidationSummary(true)
    16.<div class="form-group">
    17.@Html.LabelFor(model => model.UserName, new { @class = "control-label col-md-2" })
    18.<div class="col-md-10">
    19.@Html.EditorFor(model => model.UserName)
    20.@Html.ValidationMessageFor(model => model.UserName)
    21.</div>
    22.</div>
    23. 
    24.<div class="form-group">
    25.@Html.LabelFor(model => model.FirstName, new { @class = "control-label col-md-2" })
    26.<div class="col-md-10">
    27.@Html.EditorFor(model => model.FirstName)
    28.@Html.ValidationMessageFor(model => model.FirstName)
    29.</div>
    30.</div>
    31. 
    32.<div class="form-group">
    33.@Html.LabelFor(model => model.LastName, new { @class = "control-label col-md-2" })
    34.<div class="col-md-10">
    35.@Html.EditorFor(model => model.LastName)
    36.@Html.ValidationMessageFor(model => model.LastName)
    37.</div>
    38.</div>
    39. 
    40.<div class="form-group">
    41.@Html.LabelFor(model => model.Email, new { @class = "control-label col-md-2" })
    42.<div class="col-md-10">
    43.@Html.EditorFor(model => model.Email)
    44.@Html.ValidationMessageFor(model => model.Email)
    45.</div>
    46.</div>
    47. 
    48.<div class="form-group">
    49.<div class="col-md-offset-2 col-md-10">
    50.<input type="submit" value="存档" class="btn btn-default" />
    51.</div>
    52.</div>
    53.</div>
    54.}
    55. 
    56.<div>
    57.@Html.ActionLink("回到使用者清单画面", "Index")
    58.</div>
    59. 
    60.@section Scripts {
    61.@Scripts.Render("~/bundles/jqueryval")
    62.}

    新增Delete的Views
     





     

    用以下内容取代原程序


     

    01.@model RoleBaseProject.Models.EditUserViewModel
    02. 
    03.<h3>使用者账号删除</h3>
    04.<div>
    05.<h4>确定要删除这个使用者账号?</h4>
    06.<hr />
    07.<dl class="dl-horizontal">
    08.<dt>
    09.@Html.DisplayNameFor(model => model.UserName)
    10.</dt>
    11. 
    12.<dd>
    13.@Html.DisplayFor(model => model.UserName)
    14.</dd>
    15. 
    16.<dt>
    17.@Html.DisplayNameFor(model => model.FirstName)
    18.</dt>
    19. 
    20.<dd>
    21.@Html.DisplayFor(model => model.FirstName)
    22.</dd>
    23. 
    24.<dt>
    25.@Html.DisplayNameFor(model => model.LastName)
    26.</dt>
    27. 
    28.<dd>
    29.@Html.DisplayFor(model => model.LastName)
    30.</dd>
    31. 
    32.<dt>
    33.@Html.DisplayNameFor(model => model.Email)
    34.</dt>
    35. 
    36.<dd>
    37.@Html.DisplayFor(model => model.Email)
    38.</dd>
    39. 
    40.</dl>
    41. 
    42.@using (Html.BeginForm()) {
    43.@Html.AntiForgeryToken()
    44. 
    45.<div class="form-actions no-color">
    46.<input type="submit" value="删除" class="btn btn-default" /> |
    47.@Html.ActionLink("回到使用者清单画面", "Index")
    48.</div>
    49.}
    50.</div>

    新增Index Views
     





     

    用以下内容取代原程序


     

    01.@model IEnumerable<RoleBaseProject.Models.EditUserViewModel>
    02. 
    03.@{
    04.ViewBag.Title = "账号管理";
    05.}
    06. 
    07.<h2>账号管理</h2>
    08. 
    09.<p>
    10.@Html.ActionLink("新增账号", "Register")
    11.</p>
    12.<table class="table">
    13.<tr>
    14.<th>
    15.@Html.DisplayNameFor(model => model.UserName)
    16.</th>
    17.<th>
    18.@Html.DisplayNameFor(model => model.FirstName)
    19.</th>
    20.<th>
    21.@Html.DisplayNameFor(model => model.LastName)
    22.</th>
    23.<th>
    24.@Html.DisplayNameFor(model => model.Email)
    25.</th>
    26.<th></th>
    27.</tr>
    28. 
    29.@foreach (var item in Model) {
    30.<tr>
    31.<td>
    32.@Html.DisplayFor(modelItem => item.UserName)
    33.</td>
    34.<td>
    35.@Html.DisplayFor(modelItem => item.FirstName)
    36.</td>
    37.<td>
    38.@Html.DisplayFor(modelItem => item.LastName)
    39.</td>
    40.<td>
    41.@Html.DisplayFor(modelItem => item.Email)
    42.</td>
    43.<td>
    44.@Html.ActionLink("编辑", "Edit", new { id=item.UserName }) |
    45.@Html.ActionLink("角色", "UserRoles", new { id=item.UserName }) |
    46.@Html.ActionLink("删除", "Delete", new { id=item.UserName })
    47.</td>
    48.</tr>
    49.}
    50. 
    51.</table>
    新增好的三個View
     
     

     
    新增UserRoles.cshtml View 并 新增程序代码
     




     
    用以下内容取代原程序


    01.@model RoleBaseProject.Models.SelectUserRolesViewModel
    02.@{
    03.ViewBag.Title = "使用者角色";
    04.}
    05. 
    06.<h2>使用者角色 @Html.DisplayFor(model => model.UserName)</h2>
    07.<hr />
    08. 
    09.@using (Html.BeginForm("UserRoles", "Account", FormMethod.Post, new { encType = "multipart/form-data", name = "myform" }))
    10.{
    11.@Html.AntiForgeryToken()
    12. 
    13.<div class="form-horizontal">
    14.@Html.ValidationSummary(true)
    15.<div class="form-group">
    16.<div class="col-md-10">
    17.@Html.HiddenFor(model => model.UserName)
    18.</div>
    19.</div>
    20. 
    21.<h4>选择要加入的角色</h4>
    22.<br />
    23.<hr />
    24. 
    25.<table>
    26.<tr>
    27.<th>
    28.勾选
    29.</th>
    30.<th>
    31.角色
    32.</th>
    33.</tr>
    34.@Html.EditorFor(model => model.Roles)
    35.</table>
    36.<br />
    37.<hr />
    38. 
    39.<div class="form-group">
    40.<div class="col-md-offset-2 col-md-10">
    41.<input type="submit" value="存档" class="btn btn-default" />
    42.</div>
    43.</div>
    44.</div>
    45.}


    新增SelectRoleEditorViewModel.cshtml 在 Shared/EditorTemplates目录下
     




     

    01.@model RoleBaseProject.Models.SelectRoleEditorViewModel
    02.@Html.HiddenFor(model => model.RoleName)
    03.<tr>
    04.<td style="text-align:center">
    05.@Html.CheckBoxFor(model => model.Selected)
    06.</td>
    07.<td>
    08.@Html.DisplayFor(model => model.RoleName)
    09.</td>
    10.</tr>

    在主页面上新增”账号管理" 功能按钮



    移除主页面上的注册功能

     
     

     
    启动 Migration功能
     

     
    在Seed()方法中加入建立测试数据的程序代码
     

     
    完整程序:


    01.namespace RoleBaseProject.Migrations
    02.{
    03.using RoleBaseProject.Models;
    04.using System;
    05.using System.Data.Entity;
    06.using System.Data.Entity.Migrations;
    07.using System.Linq;
    08. 
    09.internal sealed class Configuration : DbMigrationsConfiguration<RoleBaseProject.Models.ApplicationDbContext>
    10.{
    11.public Configuration()
    12.{
    13.AutomaticMigrationsEnabled = false;
    14.}
    15. 
    16.protected override void Seed(RoleBaseProject.Models.ApplicationDbContext context)
    17.{
    18.// This method will be called after migrating to the latest version.
    19. 
    20.// You can use the DbSet<T>.AddOrUpdate() helper extension method
    21.// to avoid creating duplicate seed data. E.g.
    22.//
    23.// context.People.AddOrUpdate(
    24.// p => p.FullName,
    25.// new Person { FullName = "Andrew Peters" },
    26.// new Person { FullName = "Brice Lambson" },
    27.// new Person { FullName = "Rowan Miller" }
    28.// );
    29.//
    30.this.AddUserAndRoles();
    31.}
    32. 
    33.bool AddUserAndRoles()
    34.{
    35.bool success = false;
    36. 
    37.var idManager = new IdentityManager();
    38.success = idManager.CreateRole("Admin");
    39.if (!success == true) return success;
    40. 
    41.success = idManager.CreateRole("CanEdit");
    42.if (!success == true) return success;
    43. 
    44.success = idManager.CreateRole("User");
    45.if (!success) return success;
    46. 
    47.var newUser = new ApplicationUser()
    48.{
    49.UserName = "jatten",
    50.FirstName = "John",
    51.LastName = "Atten",
    52.Email = "jatten@typecastexception.com"
    53.};
    54. 
    55.success = idManager.CreateUser(newUser, "Password1");
    56.if (!success) return success;
    57. 
    58.success = idManager.AddUserToRole(newUser.Id, "Admin");
    59.if (!success) return success;
    60. 
    61.success = idManager.AddUserToRole(newUser.Id, "CanEdit");
    62.if (!success) return success;
    63. 
    64.success = idManager.AddUserToRole(newUser.Id, "User");
    65.if (!success) return success;
    66. 
    67.return success;
    68.}
    69.}
    70.}


    更新数据库
     





     

    执行结果
     


     

    以具有Admin角色的使用者登入后执行账户管理功能:
     

  • 相关阅读:
    java mail
    hibernate 批量处理数据
    动态规划0—1背包问题
    FreeCMS开发过程问题总结(持续更新中)
    RapeLay(电车之狼R)的结局介绍 (隐藏结局攻略)
    笔记本键盘输入错乱,字母都变成数字了
    眼下最好的JSP分页技术
    在一个字符串中找到第一个仅仅出现一次的字符
    央行力保首套房贷背后暗藏何种玄机?
    HDU2149-Good Luck in CET-4 Everybody!(博弈,打表找规律)
  • 原文地址:https://www.cnblogs.com/zhouXX/p/4104052.html
Copyright © 2020-2023  润新知