在前一篇贴文中,已探索过如何在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角色的使用者登入后执行账户管理功能: