測試環境: 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角色的使用者登入後執行帳戶管理功能:
你好 能给个完整代码吗?
回覆刪除