Error message here!

Hide Error message here!

忘记密码?

Error message here!

请输入正确邮箱

Hide Error message here!

密码丢失?请输入您的电子邮件地址。您将收到一个重设密码链接。

Error message here!

返回登录

Close

ASP.NET Core 打造一个简单的图书馆管理系统 (修正版)(二)数据库初始化、基本登录页面以及授权逻辑的建立

NanaseRuri 2019-02-14 00:03:00 阅读数:1530 评论数:0 点赞数:0 收藏数:0

前言:

本系列文章主要为我之前所学知识的一次微小的实践,以我学校图书馆管理系统为雏形所作。

本系列文章主要参考资料:

微软文档:https://docs.microsoft.com/zh-cn/aspnet/core/getting-started/?view=aspnetcore-2.1&tabs=windows

《Pro ASP.NET MVC 5》、《锋利的 jQuery》

 

 

此系列皆使用 VS2017+C/# 作为开发环境。如果有什么问题或者意见欢迎在留言区进行留言。 

项目 github 地址:https://github.com/NanaseRuri/LibraryDemo

 

 

本章内容:Identity 框架的配置、对账户进行授权的配置、数据库的初始化方法、自定义 TagHelper

 

 

 一到四为对 Student 即 Identity框架的使用,第五节为对 Admin 用户的配置

 

 

一、自定义账号和密码的限制

在 Startup.cs 的 ConfigureServices 方法中可以对 Identity 的账号和密码进行限制:1 services.AddIdentity(opts => 2 {3 4 opts.User.RequireUniqueEmail = true;5 opts.User.AllowedUserNameCharacters = "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM0123456789";6 opts.Password.RequiredLength = 6;7 opts.Password.RequireNonAlphanumeric = false;8 opts.Password.RequireLowercase = false;9 opts.Password.RequireUppercase = false;10 opts.Password.RequireDigit = false;11 }).AddEntityFrameworkStores()12 .AddDefaultTokenProviders();

RequireUniqueEmail 限制每个邮箱只能用于一个账号。

此处 AllowedUserNameCharacters 方法限制用户名能够使用的字符,需要单独输入每个字符。

剩下的设置分别为限制密码必须有符号 / 包含小写字母 / 包含大写字母 / 包含数字。

 

 

 

二、对数据库进行初始化

在此创建一个 StudentInitiator 以及一个 BookInitiator用以对数据库进行初始化:1 public classStudentInitiator2 {3 public static asyncTask Initial(IServiceProvider serviceProvider)4 {5 UserManager userManager = serviceProvider.GetRequiredService>();6 if(userManager.Users.Any())7 {8 return;9 }10 IEnumerable initialStudents = new[]11 {12 newStudent()13 {14 UserName = "U201600001",15 Name = "Nanase",16 Email = "Nanase@cnblog.com",17 PhoneNumber = "12345678910",18 Degree =Degrees.CollegeStudent,19 MaxBooksNumber = 10,20 },21 newStudent()22 {23 UserName = "U201600002",24 Name = "Ruri",25 Email = "NanaseRuri@cnblog.com",26 PhoneNumber = "12345678911",27 Degree =Degrees.DoctorateDegree,28 MaxBooksNumber = 15 29 },30 };31 32 foreach (var student ininitialStudents)33 {34 await userManager.CreateAsync(student, student.UserName.Substring(student.UserName.Length - 6,6));35 }36 }37 }

 

新建 BookInitiator 用于初始化该数据库,不知道为什么在这里会报一个 Book 重复主键的错误,但是数据确实全都插进去了:

1 public classBookInitiator2 {3 public static asyncTask BookInitial(IServiceProvider serviceProvider)4 {5 LendingInfoDbContext context = serviceProvider.GetRequiredService();6 if (!context.Books.Any() || !context.Bookshelves.Any())7 {8 Bookshelf[] bookshelfs = new[]9 {10 newBookshelf()11 {12 BookshelfId = 1,13 Location = "主校区",14 Sort = "计算机" 15 },16 newBookshelf()17 {18 BookshelfId = 2,19 Location = "主校区",20 Sort = "文学" 21 },22 newBookshelf()23 {24 BookshelfId = 3,25 Location = "东校区",26 Sort = "计算机" 27 },28 newBookshelf()29 {30 BookshelfId = 4,31 Location = "阅览室",32 Sort = "文学" 33 },34 newBookshelf()35 {36 BookshelfId = 5,37 Location = "阅览室",38 Sort = "计算机" 39 },40 };41 42 Book[] books = new[]43 {44 newBook()45 {46 Name = "精通ASP.NET MVC 5",47 BarCode = "001100987211",48 ISBN = "978-7-115-41023-8",49 State =BookState.Normal,50 FetchBookNumber = "TP393.092 19",51 Location = "主校区",52 Sort = "计算机" 53 },54 newBook()55 {56 Name = "精通ASP.NET MVC 5",57 BarCode = "001100987212",58 ISBN = "978-7-115-41023-8",59 State =BookState.Normal,60 FetchBookNumber = "TP393.092 19",61 Location = "主校区",62 Sort = "计算机" 63 },64 newBook()65 {66 Name = "精通ASP.NET MVC 5",67 BarCode = "001100987213",68 ISBN = "978-7-115-41023-8",69 State =BookState.Normal,70 FetchBookNumber = "TP393.092 19",71 Location = "东校区",72 Sort = "计算机" 73 },74 newBook()75 {76 Name = "精通ASP.NET MVC 5",77 BarCode = "001100987214",78 ISBN = "978-7-115-41023-8",79 State =BookState.Readonly,80 FetchBookNumber = "TP393.092 19",81 Location = "阅览室",82 Sort = "计算机" 83 },84 newBook()85 {86 Name = "Entity Framework实用精要",87 BarCode = "001101279682",88 ISBN = "978-7-302-48593-3",89 State =BookState.Normal,90 FetchBookNumber = "TP393.09 447",91 Location = "主校区",92 Sort = "计算机" 93 },94 newBook()95 {96 Name = "Entity Framework实用精要",97 BarCode = "001101279683",98 ISBN = "978-7-302-48593-3",99 State =BookState.Normal,100 FetchBookNumber = "TP393.09 447",101 Location = "主校区",102 Sort = "计算机" 103 },104 newBook()105 {106 Name = "Entity Framework实用精要",107 BarCode = "001101279684",108 ISBN = "978-7-302-48593-3",109 State =BookState.Normal,110 FetchBookNumber = "TP393.09 447",111 Location = "东校区",112 Sort = "计算机" 113 },114 newBook()115 {116 Name = "Entity Framework实用精要",117 BarCode = "001101279685",118 ISBN = "978-7-302-48593-3",119 State =BookState.Normal,120 FetchBookNumber = "TP393.09 447",121 Location = "东校区",122 Sort = "计算机" 123 },124 newBook()125 {126 Name = "Entity Framework实用精要",127 BarCode = "001101279686",128 ISBN = "978-7-302-48593-3",129 State =BookState.Normal,130 FetchBookNumber = "TP393.09 447",131 Location = "阅览室",132 Sort = "计算机" 133 },134 newBook()135 {136 Name = "Rails 5敏捷开发",137 BarCode = "001101290497",138 ISBN = "978-7-5680-3659-7",139 State =BookState.Normal,140 FetchBookNumber = "TP393.09 448",141 Location = "主校区",142 Sort = "计算机" 143 },144 newBook()145 {146 Name = "Rails 5敏捷开发",147 BarCode = "001101290498",148 ISBN = "978-7-5680-3659-7",149 State =BookState.Normal,150 FetchBookNumber = "TP393.09 448",151 Location = "主校区",152 Sort = "计算机" 153 },154 newBook()155 {156 Name = "Rails 5敏捷开发",157 BarCode = "001101290499",158 ISBN = "978-7-5680-3659-7",159 State =BookState.Readonly,160 FetchBookNumber = "TP393.09 448",161 Location = "主校区",162 Sort = "计算机" 163 },164 newBook()165 {166 Name = "你必须掌握的Entity Framework 6.x与Core 2.0",167 BarCode = "001101362986",168 ISBN = "978-7-5680-3659-7",169 State =BookState.Normal,170 FetchBookNumber = "TP393.09 452",171 Location = "主校区",172 Sort = "计算机" 173 },174 newBook()175 {176 Name = "你必须掌握的Entity Framework 6.x与Core 2.0",177 BarCode = "001101362987",178 ISBN = "978-7-5680-3659-7",179 State =BookState.Readonly,180 FetchBookNumber = "TP393.09 452",181 Location = "主校区",182 Sort = "计算机" 183 },184 newBook()185 {186 Name = "毛选. 第一卷",187 BarCode = "00929264",188 ISBN = "7-01-000922-8",189 State =BookState.Normal,190 FetchBookNumber = "A41 1:1",191 Location = "主校区",192 Sort = "文学" 193 },194 newBook()195 {196 Name = "毛选. 第一卷",197 BarCode = "00929265",198 ISBN = "7-01-000922-8",199 State =BookState.Normal,200 FetchBookNumber = "A41 1:1",201 Location = "主校区",202 Sort = "文学" 203 },204 newBook()205 {206 Name = "毛选. 第一卷",207 BarCode = "00929266",208 ISBN = "7-01-000922-8",209 State =BookState.Readonly,210 FetchBookNumber = "A41 1:1",211 Location = "阅览室",212 Sort = "文学" 213 },214 newBook()215 {216 Name = "毛选. 第二卷",217 BarCode = "00929279",218 ISBN = "7-01-000915-5",219 State =BookState.Normal,220 FetchBookNumber = "A41 1:2",221 Location = "主校区",222 Sort = "文学" 223 },224 newBook()225 {226 Name = "毛选. 第二卷",227 BarCode = "00929280",228 ISBN = "7-01-000915-5",229 State =BookState.Readonly,230 FetchBookNumber = "A41 1:2",231 Location = "阅览室",232 Sort = "文学" 233 },234 newBook()235 {236 Name = "毛选. 第三卷",237 BarCode = "00930420",238 ISBN = "7-01-000916-3",239 State =BookState.Normal,240 FetchBookNumber = "A41 1:3",241 Location = "主校区",242 Sort = "文学" 243 },244 newBook()245 {246 Name = "毛选. 第三卷",247 BarCode = "00930421",248 ISBN = "7-01-000916-3",249 State =BookState.Readonly,250 FetchBookNumber = "A41 1:3",251 Location = "阅览室",252 Sort = "文学" 253 },254 newBook()255 {256 Name = "毛选. 第四卷",257 BarCode = "00930465",258 ISBN = "7-01-000925-2",259 State =BookState.Normal,260 FetchBookNumber = "A41 1:4",261 Location = "主校区",262 Sort = "文学" 263 },264 newBook()265 {266 Name = "毛选. 第四卷",267 BarCode = "00930466",268 ISBN = "7-01-000925-2",269 State =BookState.Readonly,270 FetchBookNumber = "A41 1:4",271 Location = "阅览室",272 Sort = "文学" 273 }274 };275 276 BookDetails[] bookDetails = new[]277 {278 newBookDetails()279 {280 Author = "Admam Freeman",281 Name = "精通ASP.NET MVC 5",282 ISBN = "978-7-115-41023-8",283 Press = "人民邮电出版社",284 PublishDateTime = new DateTime(2016,1,1),285 SoundCassettes = "13, 642页 : 图 ; 24cm",286 Version = 1,287 FetchBookNumber = "TP393.092 19",288 Description = "ASP.NET MVC 5框架是微软ASP.NET Web平台的新进展。它提供了高生产率的编程模型,结合ASP.NET的全部优势,促成更整洁的代码架构、测试驱动开发和强大的可扩展性。本书涵盖ASP.NET MVC 5的所有开发优势技术,包括用C/#属性定义路由技术及重写过滤器技术等。且构建MVC应用程序的用户体验也有本质上的改进。其中书里也专一讲解了用新Visual Studio 2013创建MVC应用程序时的技术和技巧。本书包括完整的开发工具介绍以及对代码进行辅助编译和调试的技术。本书还涉及流行的Bootstrap JavaScript库,该库现已被纳入到MVC 5之中,为开发人员提供更广泛的多平台CSS和HTML5选项,而不必像以前那样去加载大量的第三方库。" 289 },290 newBookDetails()291 {292 Author = "吕高旭",293 Name = "Entity Framework实用精要",294 ISBN = "978-7-302-48593-3",295 Press = "清华大学出版社",296 PublishDateTime = new DateTime(2018,1,1),297 SoundCassettes = "346页 ; 26cm",298 Version = 1,299 FetchBookNumber = "TP393.09 447",300 Description = "本书通过介绍Entity Framework与 LINQ 开发实战的案例,以 Entity Framework 技术内容的讨论为主线,结合关键的 LINQ技巧说明,提供读者系统性学习 Entity Framework 所需的内容。本书旨在帮助读者进入 Entity Framework的世界,建立必要的技术能力,同时希望读者在完成本书的教学课程之后,能够更进一步地将其运用在实际的项目开发中。" 301 },302 newBookDetails()303 {304 Author = "鲁比",305 Name = "Rails 5敏捷开发",306 ISBN = "978-7-5680-3659-7",307 Press = "华中科技大学出版社",308 PublishDateTime = new DateTime(2018,1,1),309 SoundCassettes = "xxi, 451页 : 图 ; 23cm",310 Version = 1,311 FetchBookNumber = "TP393.09 448",312 Description = "本书以讲解“购书网站”案例为主线, 逐步介绍Rails的内置功能。全书分为3部分, 第一部分介绍Rails的安装、应用程序验证、Rails框架的体系结构, 以及Ruby语言知识; 第二部分用迭代方式构建应用程序, 然后依据敏捷开发模式开展测试, 最后用Capistrano完成部署; 第三部分补充日常实用的开发知识。本书既有直观的示例, 又有深入的分析, 同时涵盖了Web开发各方面的知识, 堪称一部内容全面而又深入浅出的佳作。第5版增加了关于Rails 5和Ruby 2.2新特性和最佳实践的内容。" 313 },314 newBookDetails()315 {316 Author = "汪鹏",317 Name = "你必须掌握的Entity Framework 6.x与Core 2.0",318 ISBN = "978-7-302-50017-9",319 Press = "清华大学出版社",320 PublishDateTime = new DateTime(2018,1,1),321 SoundCassettes = "X, 487页 : 图 ; 26cm",322 Version = 1,323 FetchBookNumber = "TP393.09 452",324 Description = "本书分为四篇,第一篇讲解Entity Framework 6.x的基础,包括数据库表的创建,数据的操作和数据加载方式。第二篇讲解Entity Framework 6.x进阶,包括基本原理和性能优化。第三篇讲解跨平台Entity Framework Core 2.x的基础知识和开发技巧。第四篇讲解在Entity Framework Core 2.x中解决并发问题,并给出实战开发案例。" 325 },326 newBookDetails()327 {328 Author = "毛",329 Name = "毛选. 第一卷",330 ISBN = "7-01-000914-7",331 Press = "人民出版社",332 PublishDateTime = new DateTime(1991,1,1),333 SoundCassettes = "340页 : 肖像 ; 19厘米",334 FetchBookNumber = "A41 1:1",335 Version = 2,336 Description = "《毛选》是对20世纪中国影响最大的书籍之一。" 337 },338 newBookDetails()339 {340 Author = "毛",341 Name = "毛选. 第二卷",342 ISBN = "7-01-000915-5",343 Press = "人民出版社",344 PublishDateTime = new DateTime(1991,1,1),345 SoundCassettes = "343-786页 : 肖像 ; 19厘米",346 Version = 2,347 FetchBookNumber = "A41 1:2",348 Description = "《毛选》是对20世纪中国影响最大的书籍之一。" 349 },350 newBookDetails()351 {352 Author = "毛",353 Name = "毛选. 第三卷",354 ISBN = "7-01-000916-3",355 Press = "人民出版社",356 PublishDateTime = new DateTime(1991,1,1),357 SoundCassettes = "789Ł±1120页 ; 20厘米",358 FetchBookNumber = "A41 1:3",359 Version = 2,360 Description = "《毛选》是对20世纪中国影响最大的书籍之一。" 361 },362 newBookDetails()363 {364 Author = "毛",365 Name = "毛选. 第四卷",366 ISBN = "7-01-000925-2",367 Press = "人民出版社",368 PublishDateTime = new DateTime(1991,1,1),369 SoundCassettes = "1123Ł±1517页 ; 20厘米",370 FetchBookNumber = "A41 1:4",371 Version = 2,372 Description = "《毛选》是对20世纪中国影响最大的书籍之一。" 373 },374 };375 376 var temp = from book inbooks377 from bookshelf inbookshelfs378 where book.Location == bookshelf.Location && book.Sort ==bookshelf.Sort379 select new { BarCode = book.BarCode, BookshelfId =bookshelf.BookshelfId };380 381 foreach (var bookshelf inbookshelfs)382 {383 bookshelf.Books=new List();384 }385 386 foreach (var tem intemp)387 {388 Bookshelf targetShelf = bookshelfs.Single(bookshelf => bookshelf.BookshelfId ==tem.BookshelfId);389 Book targetBook = books.Single(book => book.BarCode ==tem.BarCode);390 targetShelf.Books.Add(targetBook);391 }392 393 foreach (var bookshelf inbookshelfs)394 {395 bookshelf.MaxFetchNumber=bookshelf.Books.Max(b =>b.FetchBookNumber);396 bookshelf.MinFetchNumber=bookshelf.Books.Min(b =>b.FetchBookNumber);397 }398 399 foreach (var bookshelf inbookshelfs)400 {401 awaitcontext.Bookshelves.AddAsync(bookshelf);402 awaitcontext.SaveChangesAsync();403 }404 405 foreach (var bookDetail inbookDetails)406 {407 awaitcontext.BooksDetail.AddAsync(bookDetail);408 awaitcontext.SaveChangesAsync();409 }410 411 foreach (var book inbooks)412 {413 awaitcontext.Books.AddAsync(book);414 awaitcontext.SaveChangesAsync();415 }416 }417 }418 }View Code

 

为确保能够进行初始化,在 Startup.cs 的 Configure 方法中调用该静态方法: 1 DatabaseInitiator.Initial(app.ApplicationServices).Wait();2 BookInitiator.BookInitial(app.ApplicationServices).Wait();

 

Initial 方法中 serviceProvider 参数将在传入 ConfigureServices 方法调用后的 ServiceProvider,此时在 Initial 方法中初始化的数据也会使用 ConfigureServices 中对账号和密码的限制。

此处我们使用账号的后六位作为密码。启动网页后查看数据库的数据:

 

 

 

 

 

 

 

 

 

三、建立验证所用的控制器以及视图

 

首先创建一个视图模型用于存储账号的信息,为了方便实现多种登录方式,此处创建一个 LoginType 枚举:

[UIHint] 特性构造函数传入一个字符串用来告知对应属性在使用 Html.EditorFor() 时用什么模板来展示数据。1 public enumLoginType2 {3 UserName,4 Email,5 Phone6 }7 8 public classLoginModel9 {10 [Required(ErrorMessage = "请输入您的学号 / 邮箱 / 手机号码")]11 [Display(Name = "学号 / 邮箱 / 手机号码")]12 public string Account { get; set; }13 14 [Required(ErrorMessage = "请输入您的密码")]15 [UIHint("password")]16 [Display(Name = "密码")]17 public string Password { get; set; }18 19 [Required]20 public LoginType LoginType { get; set; }21 }

 

 使用支架特性创建一个 StudentAccountController

 

StudentAccount 控制器:

第 5 行判断是否授权以避免多余的授权:1 public classStudentAccountController : Controller2 {3 public IActionResult Login(stringreturnUrl)4 {5 if(HttpContext.User.Identity.IsAuthenticated)6 {7 return RedirectToAction("AccountInfo");8 }9 10 LoginModel loginInfo = newLoginModel();11 ViewBag.returnUrl =returnUrl;12 returnView(loginInfo);13 }14 }

 

在在 Login 视图中添加多种登录方式,并使视图更加清晰,创建了一个 LoginTypeTagHelper ,TagHelper 可制定自定义 HTML 标记并在最终生成视图时转换成标准的 HTML 标记。1 [HtmlTargetElement("LoginType")]2 public classLoginTypeTagHelper:TagHelper3 {4 public string[] LoginType { get; set; }5 6 public overrideTask ProcessAsync(TagHelperContext context, TagHelperOutput output)7 {8 foreach (var loginType inLoginType)9 {10 switch(loginType)11 {12 case "UserName": output.Content.AppendHtml($"");13 break;14 case "Email": output.Content.AppendHtml(GetOption(loginType, "邮箱"));15 break;16 case "Phone": output.Content.AppendHtml(GetOption(loginType, "手机号码"));17 break;18 default: break;19 }20 }21 returnTask.CompletedTask;22 }23 24 private static string GetOption(string loginType,stringinnerText)25 {26 return $"";27 }28 }

 

Login 视图:

25 行中使用了刚建立的 LoginTypeTagHelper:1 @model LoginModel2 3 @{4 ViewData["Title"] = "Login";5 }6 7

Login

8
9
10
11
12 13
14 15 16
17
18 19 20
21
22 23 27
28 29

 

 

然后创建一个用于对信息进行验证的动作方法。

 

为了获取数据库的数据以及对数据进行验证授权,需要通过 DI(依赖注入) 获取对应的 UserManager 和 SignInManager 对象,在此针对 StudentAccountController 的构造函数进行更新。

StudentAccountController 整体:1 [Authorize]2 public classStudentAccountController : Controller3 {4 private UserManager_userManager;5 private SignInManager_signInManager;6 7 public StudentAccountController(UserManager studentManager, SignInManagersignInManager)8 {9 _userManager =studentManager;10 _signInManager =signInManager;11 }12 13 [AllowAnonymous]14 public IActionResult Login(stringreturnUrl)15 {16 if(HttpContext.User.Identity.IsAuthenticated)17 {18 return RedirectToAction("AccountInfo");19 }20 21 LoginModel loginInfo = newLoginModel();22 ViewBag.returnUrl =returnUrl;23 returnView(loginInfo);24 }25 26 [HttpPost]27 [ValidateAntiForgeryToken]28 [AllowAnonymous]29 public async Task Login(LoginModel loginInfo, stringreturnUrl)30 {31 if(ModelState.IsValid)32 {33 Student student =awaitGetStudentByLoginModel(loginInfo);34 35 if (student == null)36 {37 returnView(loginInfo);38 }39 SignInResult signInResult = await _signInManager.PasswordSignInAsync(student, loginInfo.Password, false, false);40 41 if(signInResult.Succeeded)42 {43 return Redirect(returnUrl ?? "/StudentAccount/"+nameof(AccountInfo));44 }45 46 ModelState.AddModelError("", "账号或密码错误");47 48 }49 50 returnView(loginInfo);51 }52 53 publicIActionResult AccountInfo()54 {55 returnView(CurrentAccountData());56 }57 58 DictionaryCurrentAccountData()59 {60 var userName =HttpContext.User.Identity.Name;61 var user =_userManager.FindByNameAsync(userName).Result;62 63 return new Dictionary()64 {65 ["学号"]=userName,66 ["姓名"]=user.Name,67 ["邮箱"]=user.Email,68 ["手机号"]=user.PhoneNumber,69 };70 }71 }

userManager 以及  signInManager 将通过 DI 获得实例;[ValidateAntiForgeryToken] 特性用于防止 XSRF 攻击;returnUrl 参数用于接收或返回之前正在访问的页面,在此处若 returnUrl 为空则返回 AccountInfo 页面;[Authorize] 特性用于确保只有已授权的用户才能访问对应动作方法;CurrentAccountData 方法用于获取当前用户的信息以在 AccountInfo 视图中呈现。

 

由于未进行授权,在此直接访问 AccountInfo 方法默认会返回 /Account/Login 页面请求验证,可通过在 Startup.cs 的 ConfigureServices 方法进行配置以覆盖这一行为,让页面默认返回 /StudentAccount/Login :1 services.ConfigureApplicationCookie(opts => 2 {3 opts.LoginPath = "/StudentAccount/Login";4 }

 

为了使 [Authorize] 特性能够正常工作,需要在 Configure 方法中使用 Authentication 中间件,如果没有调用 app.UseAuthentication(),则访问带有 [Authorize] 的方法会再度要求进行验证。中间件的顺序很重要:1 app.UseAuthentication();2 app.UseHttpsRedirection();3 app.UseStaticFiles();4 app.UseCookiePolicy();

 

直接访问 AccountInfo 页面:

 

输入账号密码进行验证:

 

验证之后返回 /StudentAccount/AccountInfo 页面:

 

 

 

四、创建登出网页

简单地调用 SignOutAsync 用以清除当前 Cookie 中的授权信息。1 public async Task Logout(stringreturnUrl)2 {3 await_signInManager.SignOutAsync();4 if (returnUrl == null)5 {6 return View("Login");7 }8 9 returnRedirect(returnUrl);10 }

 

同时在 AccountInfo 添加登出按钮:1 @model Dictionary 2 @{3 ViewData["Title"] = "AccountInfo";4 }5

账户信息

6
    7 @foreach (var info inModel)8 {9
  • @info.Key: @Model[info.Key]
  • 10 }11
12
13 登出

 

 

 

登出后返回 Login 页面,同时 AccountInfo 页面需要重新进行验证。

 

附加使用邮箱以及手机号验证的测试:

 

 

 

 

 

五、基于 Role 的 Identity 授权

修改 StudentInitial 类,添加名为 admin 的学生数组并使用 AddToRoleAsync 为用户添加身份。在添加 Role 之前需要在 RoleManager 对象中使用 Create 方法为 Role 数据库添加特定的 Role 字段:1 public classStudentInitiator2 {3 public static asyncTask InitialStudents(IServiceProvider serviceProvider)4 {5 UserManager userManager = serviceProvider.GetRequiredService>();6 RoleManager roleManager = serviceProvider.GetRequiredService>();7 if(userManager.Users.Any())8 {9 return;10 }11 12 if (await roleManager.FindByNameAsync("Admin")==null)13 {14 await roleManager.CreateAsync(new IdentityRole("Admin"));15 }16 17 if (await roleManager.FindByNameAsync("Student")==null)18 {19 await roleManager.CreateAsync(new IdentityRole("Student"));20 }21 22 IEnumerable initialStudents = new[]23 {24 newStudent()25 {26 UserName = "U201600001",27 Name = "Nanase",28 Email = "Nanase@cnblog.com",29 PhoneNumber = "12345678910",30 Degree =Degrees.CollegeStudent,31 MaxBooksNumber = 10,32 },33 newStudent()34 {35 UserName = "U201600002",36 Name = "Ruri",37 Email = "NanaseRuri@cnblog.com",38 PhoneNumber = "12345678911",39 Degree =Degrees.DoctorateDegree,40 MaxBooksNumber = 15 41 }42 };43 44 IEnumerable initialAdmins = new[]45 {46 newStudent()47 {48 UserName = "A000000000",49 Name="Admin0000",50 Email = "Admin@cnblog.com",51 PhoneNumber = "12345678912",52 Degree =Degrees.CollegeStudent,53 MaxBooksNumber = 20 54 },55 newStudent()56 {57 UserName = "A000000001",58 Name = "Admin0001",59 Email = "123456789@qq.com",60 PhoneNumber = "12345678910",61 Degree =Degrees.CollegeStudent,62 MaxBooksNumber = 20 63 },64 };65 foreach (var student ininitialStudents)66 {67 await userManager.CreateAsync(student, student.UserName.Substring(student.UserName.Length - 6, 6));68 }69 foreach (var admin ininitialAdmins)70 {71 await userManager.CreateAsync(admin, "zxcZXC!123");72 await userManager.AddToRoleAsync(admin, "Admin");73 }74 }75 }

 

  对 ConfigureServices 作进一步配置,添加 Cookie 的过期时间和不满足 Authorize 条件时返回的 Url:1 services.ConfigureApplicationCookie(opts => 2 { 3 opts.Cookie.HttpOnly = true;4 opts.LoginPath = "/StudentAccount/Login"; 5 opts.AccessDeniedPath = "/StudentAccount/Login"; 6 opts.ExpireTimeSpan=TimeSpan.FromMinutes(5);7 });

  则当 Role 不为 Admin 时将返回 /StudentAccount/Login 而非默认的 /Account/AccessDeny。

 

 

然后新建一个用以管理学生信息的 AdminAccount 控制器,设置 [Authorize] 特性并指定 Role 属性,使带有特定 Role 的身份才可以访问该控制器。1 [Authorize(Roles = "Admin")]2 public classAdminAccountController : Controller3 {4 private UserManager_userManager;5 6 public AdminAccountController(UserManageruserManager)7 {8 _userManager =userManager;9 }10 11 publicIActionResult Index()12 {13 ICollection students =_userManager.Users.ToList();14 returnView(students);15 }16 }

 

Index 视图:1 @using LibraryDemo.Models.DomainModels2 @model IEnumerable 3 @{4 ViewData["Title"] = "AccountInfo";5 Student stu = newStudent();6 }7 8 9 96 97

学生信息

98 99
100 101 102
103 104 105
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 @if (!@Model.Any())121 {122 123 }124 else 125 {126 foreach (var student inModel)127 {128 129 130 131 132 133 134 135 136 137 }138 }139 140
@Html.LabelFor(m => stu.UserName)@Html.LabelFor(m => stu.Name)@Html.LabelFor(m => stu.Degree)@Html.LabelFor(m => stu.PhoneNumber)@Html.LabelFor(m => stu.Email)@Html.LabelFor(m => stu.MaxBooksNumber)
未有学生信息
@student.UserName@student.Name@Html.DisplayFor(m => student.Degree)@student.PhoneNumber@student.Email@student.MaxBooksNumber

 

使用 Role 不是 Admin 的账户登录:

 

 

  使用 Role 为 Admin 的账户登录:

 

版权声明
本文为[NanaseRuri]所创,转载请带上原文链接,感谢
https://www.cnblogs.com/gokoururi/p/10372471.html