asp网站源码分享封装?asp网站源码免费版

今天给各位分享asp网站源码分享封装的知识,其中也会对asp网站源码免费版进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!

我们经常使用的各类网站和App均会涉及注册、登录和修改密码等功能,登录系统后,有些功能会提示没有权限,甚至有些位置我们无法访问,这些都是系统权限和认证的体现。

我们从本章及后面的章节中,将学习在ASP.NETCore应用程序中使用ASP.NETCoreIdentity实现安全认证相关功能所需要掌握的知识。

本章主要向读者介绍如下内容。

什么是ASP.NETCoreIdentity。如何在系统中启用Identity服务。UserManager与SignInManager的API介绍及使用。登录用户的Cookie管理。

21.1ASP.NETCoreIdentity介绍

ASP.NETCoreIdentity是一个会员身份系统,早期它的名字是Membership,当然那是一段“古老”的历史,现在我们来了解全新的Identity。它允许我们创建、读取、更新和删除账户。支持账号验证、身份验证、授权、恢复密码和SMS双因子身份验证。它还支持微软、Facebook和Google等第三方登录提供商。它提供了一个丰富的API,并且这些API还可以进行大量的扩展。我们将在本书的后面实现这些功能。

添加ASP.NETCoreIdentity服务

这里采用的是EFCore,因为要让我们的系统支持Identity服务,所以需要安装它的程序包。打开NuGet管理器,安装Microsoft.AspNetCore.Identity.EntityFrameworkCore即可。

以下是添加和配置ASP.NETCoreIdentity服务的步骤。

使AppDbContext继承类IdentityDbContext,然后引入命名空间,代码如下。

publicclassAppDbContext:IdentityDbContext\n{\n//其余代码\n}

应用程序AppDbContextDbContext类必须继承IdentityDbContext类而不是DbContext类。因为IdentityDbContext提供了管理SQLServer中的Identity表所需的所有DbSet属性,所以将看到ASP.NETCoreIdentity框架中要生成的所有数据库表。如果浏览IdentityDbContext类的定义(按F12键可以看到),则将看到它继承自DbContext类。因此,如果类继承自IdentityDbContext类,那么不必显式继承DbContext类。

配置ASP.NETCoreIdentity服务。在Startup类的ConfigureServices()方法中,添加以下代码行。

services.AddIdentity<IdentityUser,IdentityRole>()\n.AddEntityFrameworkStores<AppDbContext>();

AddIdentity()方法是指为系统提供默认的用户和角色类型的身份验证系统。IdentityUser类由ASP.NETCore提供,包含UserName、PasswordHash和Email等属性。这是ASP.NETCoreIdentity框架默认使用的类,用于管理应用程序的注册用户。如果读者希望存储有关注册用户的其他信息,比如性别、城市等,则需要创建一个派生自IdentityUser的自定义类。在此自定义类中添加所需的其他属性,然后插入此类而不是内置的IdentityUser类。我们将在后面的章节中学习如何执行此操作。同样,IdentityRole也是ASP.NETCoreIdentity提供的内置类,包含角色信息。使用EntityFrameWorkCore从基础SQLServer数据库存储和查询注册用户的角色信息。使用AddEntityFrameworkStores()方法,然后指定DbContext类作为泛型参数。

接下来,将Authentication()中间件添加到请求管道,代码如下。

publicvoidConfigure(IApplicationBuilderapp,IWebHostEnvironmentenv)\n{\n//如果环境是DevelopmentserveDeveloperExceptionPage\nif(env.IsDevelopment())\n{\napp.UseDeveloperExceptionPage();\n}\n//否则显示用户友好的错误页面\nelseif(env.IsStaging()||env.IsProduction()||env.IsEnvironment(&34;))\n{\napp.UseExceptionHandler(&34;);\napp.UseStatusCodePagesWithReExecute(&34;);\n}\n\n//使用纯静态文件支持的中间件,而不使用带有终端的中间件\napp.UseStaticFiles();\n//添加验证中间件\napp.UseAuthentication();\n\napp.UseRouting();\napp.UseEndpoints(endpoints=>\n{\nendpoints.MapControllerRoute(\nname:&34;,\npattern:&34;);\n});\n}

在Startup类的Configure()方法中,调用UseAuthentication()方法将Authentication()中间件添加到应用程序的请求处理管道中。我们希望能够在请求到达MVC中间件之前对用户进行身份验证。因此,在请求处理管道的UseRouting()中间件之前添加认证中间件。这很重要,因为我们之前讲过中间件的添加顺序不能乱。

现在开始添加身份迁移。在VisualStudio中的程序包控制台窗口执行以下命令以添加新迁移。

Add-MigrationAddingIdentity

此迁移包含用于创建ASP.NETCoreIdentity系统所需的表的代码。

如果运行,则会出现以下错误。

Theentitytype&39;requiresaprimarykeytobedefined.

之前因为要封装Seed()方法,所以重写OnModelCreating()方法。出现这个错误是因为我们在DbContext类中重写了OnModelCreating()方法,但未调用基本IdentityDbContext类OnModelCreating()方法。

Identity表的键映射在IdentityDbContext类的OnModelCreating()方法中。因此,要解决这个错误,需要做的是,调用基类OnModelCreating()使用该方法的基础关键字,代码如下。

publicclassAppDbContext:IdentityDbContext\n{\n\npublicAppDbContext(DbContextOptions<AppDbContext>options):base(options)\n{\n}\npublicDbSet<Student>Students{get;set;}\nprotectedoverridevoidOnModelCreating(ModelBuildermodelBuilder)\n{\nbase.OnModelCreating(modelBuilder);\nmodelBuilder.Seed();\n}\n}

执行Update-Database命令以应用迁移记录并创建所需的身份表,如图21.1所示。

图21.1

21.2使用ASP.NETCoreIdentity注册新用户

现在已经创建好了表的信息,接下来我们增加一个注册功能,让用户能够注册到系统中。

新用户注册视图应如图21.2所示。为了能够注册为新用户,需要邮箱地址和密码两个字段。

图21.2

21.2.1RegisterViewModel视图模型

我们将使用RegisterViewModel类作为Register视图的模型,它负责将视图中的信息传递给控制器。为了验证信息是否正确,我们使用了几个ASP.NETCore验证属性。在之前的章节中详细说明过这些属性和模型验证。

usingSystem.ComponentModel.DataAnnotations;\n\n\nnamespaceMockSchoolManagement.ViewModels\n{\npublicclassRegisterViewModel\n{\n\n[Required]\n[EmailAddress]\n[Display(Name=&34;)]\n\npublicstringEmail{get;set;}\n\n[Required]\n[DataType(DataType.Password)]\n[Display(Name=&34;)]\n\npublicstringPassword{get;set;}\n\n[DataType(DataType.Password)]\n[Display(Name=&34;)]\n[Compare(&34;,\nErrorMessage=&34;)]\npublicstringConfirmPassword{get;set;}\n}\n}

在这里我们添加了DataType特性,它的主要作用是指定比数据库内部类型更具体的数据类型。DataType枚举提供了多种数据类型,比如日期、时间、电话号码、货币和邮箱地址等。但是请注意,DataType特性不提供任何验证,它主要服务于我们的视图文件,比如,DataType.EmailAddress可以在视图中创建mailto:链接,DataType.Date则会在支持HTML5的浏览器中提供日期选择器。

21.2.2账户控制器

账户控制器(AccountController)是指所有与账户相关的CRUD(增加、读取、更新和删除)操作都将在此控制器中。目前我们只有Register()操作方法,可以通过向/account/register发出GET请求来实现此操作方法。

usingMicrosoft.AspNetCore.Mvc;\n\nnamespaceMockSchoolManagement.Controllers\n{\npublicclassAccountController:Controller\n{\n[HttpGet]\npublicIActionResultRegister()\n{\nreturnView();\n}\n}\n}

21.2.3注册视图中的代码

将此视图放在Views/Account文件夹中,此视图的模型是我们在前面创建的RegisterViewModel。

@modelRegisterViewModel\n@{ViewBag.Title=&34;;}\n\n<h1>用户注册</h1>\n\n<divclass=&34;>\n<divclass=&34;>\n<formmethod=&34;>\n<divasp-validation-summary=&34;class=&34;></div>\n<divclass=&34;>\n<labelasp-for=&34;></label>\n<inputasp-for=&34;class=&34;/>\n<spanasp-validation-for=&34;class=&34;></span>\n</div>\n<divclass=&34;>\n<labelasp-for=&34;></label>\n<inputasp-for=&34;class=&34;/>\n<spanasp-validation-for=&34;class=&34;></span>\n</div>\n<divclass=&34;>\n<labelasp-for=&34;></label>\n<inputasp-for=&34;class=&34;/>\n<spanasp-validation-for=&34;class=&34;></span>\n</div>\n<buttontype=&34;class=&34;>注册</button>\n</form>\n</div>\n</div>

21.2.4添加注册按钮

在布局视图中添加注册按钮,我们需要在_Layout.cshtml文件中找到ID为collapsibleNavbar的导航菜单栏,在下方添加注册按钮,导航到对应的视图,代码如下。

<divid=&34;class=&34;>\n<ulclass=&34;>\n<liclass=&34;>\n<aclass=&34;asp-controller=&34;asp-action=&34;>学生列表</a>\n</li>\n<liclass=&34;>\n<aclass=&34;asp-controller=&34;asp-action=&34;>添加学生</a>\n</li>\n</ul>\n<ulclass=&34;>\n<liclass=&34;>\n<aclass=&34;asp-controller=&34;asp-action=&34;>注册</a>\n</li>\n</ul>\n</div>

运行项目后,单击注册按钮即可看到图21.2所示的效果图,接下来我们实现处理HttpPOST请求到/account/register的Register()操作方法。然后通过表单Taghelpers将数据发布到ASP.NETCoreIdentity中创建账户。

21.3UserManager和SignInManager服务

在本节我们学习使用ASP.NETCoreIdentity提供的UserManager服务创建新用户,然后使用其提供的SignInManager服务来登录用户。

UserManager<IdentityUser>类包含管理基础数据存储中的用户所需的方法。比如,此类具有CreateAsync()、DeleteAsync()和UpdateAsync()等方法来创建、删除和更新用户,如图21.3所示。

图21.3

SignInManager<IdentityUser>类包含用户登录所需的方法。比如,SignInManager类具有SignInAsync()、SignOutAsync()等方法来登录和注销用户,如图21.4所示。

UserManager和SignInManager服务都需要使用构造函数注入AccountController,并且这两个服务都接收泛型参数。这些服务接收泛型参数的User类。目前,我们使用内置的IdentityUser类作为泛型参数的参数。这两个服务的通用参数User是一个扩展类。这意味着,我们可以自定义与用户有关的信息和其他数据,来创建我们的自定义用户。

图21.4

我们可以声明自己的自定义类作为泛型参数,而不是内置的IdentityUser类。

以下是AccountController的完整代码。

usingMicrosoft.AspNetCore.Identity;\nusingMicrosoft.AspNetCore.Mvc;\nusingMockSchoolManagement.ViewModels;\nusingSystem.Threading.Tasks;\n\nnamespaceMockSchoolManagement.Controllers\n{\npublicclassAccountController:Controller\n{\nprivateUserManager<IdentityUser>_userManager;\nprivateSignInManager<IdentityUser>_signInManager;\n\npublicAccountController(UserManager<IdentityUser>userManager,\nSignInManager<IdentityUser>signInManager)\n{\nthis._userManager=userManager;\nthis._signInManager=signInManager;\n}\n\n[HttpGet]\npublicIActionResultRegister()\n{\nreturnView();\n}\n\n[HttpPost]\npublicasyncTask<IActionResult>Register(RegisterViewModelmodel)\n{\nif(ModelState.IsValid)\n{\n//将数据从RegisterViewModel复制到IdentityUser\nvaruser=newIdentityUser\n{\nUserName=model.Email,\nEmail=model.Email\n};\n\n//将用户数据存储在AspNetUsers数据库表中\nvarresult=await_userManager.CreateAsync(user,model.Password);\n\n//如果成功创建用户,则使用登录服务登录用户信息\n//并重定向到HomeController的索引操作\nif(result.Succeeded)\n{\nawait_signInManager.SignInAsync(user,isPersistent:false);\nreturnRedirectToAction(&34;,&34;);\n}\n\n//如果有任何错误,则将它们添加到ModelState对象中\n//将由验证摘要标记助手显示到视图中\nforeach(varerrorinresult.Errors)\n{\nModelState.AddModelError(string.Empty,error.Description);\n}\n}\n\nreturnView(model);\n}\n}\n}

此时,如果读者运行项目并提供有效的邮箱地址和密码,则它会在SQLServer数据库的AspNetUsers表中创建账户。读者可以从VisualStudio的SQLServer对象资源管理器中查看此数据,如图21.5所示。

图21.5

21.3.1ASP.NETCoreIdentity中对密码复杂度的处理

在刚刚注册的时候,我们发现有两个问题。

密码验证机制太复杂了。它是英文的,对于我们来说支持不是很友好。

这是因为ASP.NETCoreIdentityOptions类在ASP.NETCore中用于配置密码复杂性规则。默认情况下,ASP.NETCore身份不允许创建简单的密码来保护我们的应用程序免受自动暴力攻击。

当我们尝试使用像abc这样的简单密码注册新账户时,会显示创建失败,读者将看到如图21.6所示的验证错误。

图21.6

我们在图21.6中看到中文提示,后面的章节会告诉读者如何配置。

21.3.2ASP.NETCoreIdentity密码默认设置

在ASP.NETCoreIdentity中,密码默认设置在PasswordOptions类中。读者可以在ASP.NETCoreGitHub仓库中找到此类的源代码。只需在仓库中搜索PasswordOptions类。

代码如下。

publicclassPasswordOptions\n{\npublicintRequiredLength{get;set;}=6;\npublicintRequiredUniqueChars{get;set;}=1;\npublicboolRequireNonAlphanumeric{get;set;}=true;\npublicboolRequireLowercase{get;set;}=true;\npublicboolRequireUppercase{get;set;}=true;\npublicboolRequireDigit{get;set;}=true;\n}

相关参数的说明如表21.1(略)所示。

21.3.3覆盖ASP.NETCore身份中的密码默认设置

我们可以通过在Startup类的ConfigureServices()方法中使用IServiceCollection接口的Configure()方法来实现这一点。

services.Configure<IdentityOptions>(options=>\n{\noptions.Password.RequiredLength=6;\noptions.Password.RequiredUniqueChars=3;\noptions.Password.RequireNonAlphanumeric=false;\noptions.Password.RequireLowercase=false;\noptions.Password.RequireUppercase=false;\n\n});

也可以在添加身份服务时执行此操作,代码如下。

services.AddIdentity<IdentityUser,IdentityRole>(options=>\n{\noptions.Password.RequiredLength=6;\noptions.Password.RequiredUniqueChars=3;\noptions.Password.RequireNonAlphanumeric=false;\n})\n.AddEntityFrameworkStores<AppDbContext>();

当然,在这里推荐使用IdentityOptions的形式进行配置,因为它可以作为一个独立服务,而不是嵌套在AddIdentity()方法中。

IdentityOptions对象中除了Password的配置信息,还有用户、登录、策略等配置信息,我们可以根据不同的场景进行灵活的配置。

UserOptions。SignInOptions。LockoutOptions。TokenOptions。StoreOptions。ClaimsIdentityOptions。

21.3.4修改中文提示的错误信息

Identity提供了AddErrorDescriber()方法,可方便我们进行错误内容的配置和处理。

ASP.NETCore默认提供的都是英文提示,我们可以将它们修改为中文。现在我们创建一个CustomIdentityErrorDescriber的类文件,路径为根目录下创建的CustomerMiddlewares文件夹,然后继承IdentityErrorDescriber服务,添加以下代码。

publicclassCustomIdentityErrorDescriber:IdentityErrorDescriber\n{\n\npublicoverrideIdentityErrorDefaultError()\n{\nreturnnewIdentityError{Code=nameof(DefaultError),Description=$&34;};\n}\n\npublicoverrideIdentityErrorConcurrencyFailure()\n{\nreturnnewIdentityError{Code=nameof(ConcurrencyFailure),Description=&34;};\n}\n\npublicoverrideIdentityErrorPasswordMismatch()\n{\nreturnnewIdentityError{Code=nameof(PasswordMismatch),Description=&34;};\n}\n\npublicoverrideIdentityErrorInvalidToken()\n{\nreturnnewIdentityError{Code=nameof(InvalidToken),Description=&34;};\n}\n\npublicoverrideIdentityErrorLoginAlreadyAssociated()\n{\nreturnnewIdentityError{Code=nameof(LoginAlreadyAssociated),Description=&34;};\n}\n\npublicoverrideIdentityErrorInvalidUserName(stringuserName)\n{\nreturnnewIdentityError{Code=nameof(InvalidUserName),Description=$&39;{userName}&34;};\n}\n\npublicoverrideIdentityErrorInvalidEmail(stringemail)\n{\nreturnnewIdentityError{Code=nameof(InvalidEmail),Description=$&39;{email}&34;};\n}\n\npublicoverrideIdentityErrorDuplicateUserName(stringuserName)\n{\nreturnnewIdentityError{Code=nameof(DuplicateUserName),Description=$&39;{userName}&34;};\n}\n\npublicoverrideIdentityErrorDuplicateEmail(stringemail)\n{\nreturnnewIdentityError{Code=nameof(DuplicateEmail),Description=$&39;{email}&34;};\n}\n\npublicoverrideIdentityErrorInvalidRoleName(stringrole)\n{\nreturnnewIdentityError{Code=nameof(InvalidRoleName),Description=$&39;{role}&34;};\n}\n\npublicoverrideIdentityErrorDuplicateRoleName(stringrole)\n{\nreturnnewIdentityError{Code=nameof(DuplicateRoleName),Description=$&39;{role}&34;};\n}\n\npublicoverrideIdentityErrorUserAlreadyHasPassword()\n{\nreturnnewIdentityError{Code=nameof(UserAlreadyHasPassword),Description=&34;};\n}\n\npublicoverrideIdentityErrorUserLockoutNotEnabled()\n{\nreturnnewIdentityError{Code=nameof(UserLockoutNotEnabled),Description=&34;};\n}\n\npublicoverrideIdentityErrorUserAlreadyInRole(stringrole)\n{\nreturnnewIdentityError{Code=nameof(UserAlreadyInRole),Description=$&39;{role}&34;};\n}\npublicoverrideIdentityErrorUserNotInRole(stringrole)\n{\nreturnnewIdentityError{Code=nameof(UserNotInRole),Description=$&39;{role}&34;};\n}\n\npublicoverrideIdentityErrorPasswordTooShort(intlength)\n{\nreturnnewIdentityError{Code=nameof(PasswordTooShort),Description=$&34;};\n}\n\npublicoverrideIdentityErrorPasswordRequiresNonAlphanumeric()\n{\nreturnnewIdentityError\n{\nCode=nameof(PasswordRequiresNonAlphanumeric),\nDescription=&34;\n};\n}\n\npublicoverrideIdentityErrorPasswordRequiresDigit()\n{\nreturnnewIdentityError{Code=nameof(PasswordRequiresDigit),Description=$&39;0&39;9&34;};\n}\n\n\npublicoverrideIdentityErrorPasswordRequiresUniqueChars(intuniqueChars)\n{\nreturnnewIdentityError{Code=nameof(PasswordRequiresUniqueChars),Description=$&34;};\n}\n\npublicoverrideIdentityErrorPasswordRequiresLower()\n{\nreturnnewIdentityError{Code=nameof(PasswordRequiresLower),Description=&39;a&39;z&34;};\n}\n\npublicoverrideIdentityErrorPasswordRequiresUpper()\n{\nreturnnewIdentityError{Code=nameof(PasswordRequiresUpper),Description=&39;A&39;Z&34;};\n}\n\n\n\n}

回到Startup类的ConfigureServices()方法中,在AddIdentity()服务中使用AddErrorDescriber()方法覆盖默认的错误提示内容,代码如下。

services.AddIdentity<IdentityUser,IdentityRole>().AddErrorDescriber<CustomIdentityErrorDescriber>().AddEntityFrameworkStores<AppDbContext>();

配置完成之后,提示变为中文,注册时密码长度达到6位即可。

21.4登录状态及注销功能的实现

在本节中我们学习如何判断用户是否登录,以及注册、登录和注销等功能是否可实现。

首先来看一看如何在ASP.NETCore中实现注销功能。如果用户未登录,则显示登录和注册按钮,如图21.7所示。

图21.7

如果用户已登录,请隐藏登录和注册按钮并显示注销按钮,如图21.8所示。

图21.8

我们需要在_Layout.cshtml文件中找到ID为collapsibleNavbar的导航菜单栏,修改代码如下。

在下方代码中注入了SignInManager,以便我们检查用户是否已登录,来决定显示和隐藏的内容。

@usingMicrosoft.AspNetCore.Identity@injectSignInManager<IdentityUser>\n_signInManager\n<divclass=&34;id=&34;>\n<ulclass=&34;>\n<liclass=&34;>\n<aclass=&34;asp-controller=&34;asp-action=&34;>学生列表</a>\n</li>\n<liclass=&34;>\n<aclass=&34;asp-controller=&34;asp-action=&34;>添加学生</a>\n</li>\n</ul>\n<ulclass=&34;>\n@*如果用户已登录,则显示注销链接*@@if(_signInManager.IsSignedIn(User)){\n<liclass=&34;>\n<formmethod=&34;asp-controller=&34;asp-action=&34;>\n<buttontype=&34;style=&34;\nclass=&34;>\n注销@User.Identity.Name\n</button>\n</form>\n</li>\n}else{\n<liclass=&34;>\n<aclass=&34;asp-controller=&34;asp-action=&34;>\n注册\n</a>\n</li>\n<liclass=&34;>\n<aclass=&34;asp-controller=&34;asp-action=&34;>\n登录\n</a>\n</li>\n}\n</ul>\n</div>\n</IdentityUser>

然后在AccountController中添加以下Logout()方法。

[HttpPost]\npublicasyncTask<IActionResult>Logout()\n{\nawait_signInManager.SignOutAsync();\nreturnRedirectToAction(&34;,&34;);\n}

请注意,我们使用POST请求将用户注销,而不使用GET请求,因为该方法可能会被滥用。恶意者可能会诱骗用户单击某张图片,将图片的src属性设置为应用程序注销URL,这样会造成用户在不知不觉中退出了账户。

21.5ASP.NETCoreIdentity中的登录功能实现

在本节中,我们将讨论使用ASP.NETCoreIdentity的API在ASP.NETCore应用程序中实现登录功能。要在ASP.NETCore应用程序中实现登录功能,我们需要实现以下功能。

登录视图模型。登录视图。AccountController中的两个Login()操作方法。

21.5.1LoginViewModel登录视图模型

要在系统中登录用户,则需要其邮箱、用户名、密码以及使其选择是否需要持久性Cookie或会话Cookie。

publicclassLoginViewModel\n{\n\n[Required]\n[EmailAddress]\npublicstringEmail{get;set;}\n\n[Required]\n[DataType(DataType.Password)]\npublicstringPassword{get;set;}\n\n[Display(Name=&34;)]\npublicboolRememberMe{get;set;}\n}

21.5.2登录视图的代码

登录视图的代码如下。

@modelLoginViewModel\n@{ViewBag.Title=&34;;}\n\n<h1>用户登录</h1>\n\n<divclass=&34;>\n<divclass=&34;>\n<formmethod=&34;>\n<divasp-validation-summary=&34;class=&34;></div>\n<divclass=&34;>\n<labelasp-for=&34;></label>\n<inputasp-for=&34;class=&34;/>\n<spanasp-validation-for=&34;class=&34;></span>\n</div>\n<divclass=&34;>\n<labelasp-for=&34;></label>\n<inputasp-for=&34;class=&34;/>\n<spanasp-validation-for=&34;class=&34;></span>\n</div>\n<divclass=&34;>\n<divclass=&34;>\n<labelasp-for=&34;>\n<inputasp-for=&34;/>\n@Html.DisplayNameFor(m=>m.RememberMe)\n</label>\n</div>\n</div>\n<buttontype=&34;class=&34;>登录</button>\n</form>\n</div>\n</div>

21.5.3AccountController中的Login()操作方法

usingMicrosoft.AspNetCore.Identity;\nusingMicrosoft.AspNetCore.Mvc;\nusingMockSchoolManagement.ViewModels;\nusingSystem.Threading.Tasks;\n\nnamespaceMockSchoolManagement.Controllers\n{\npublicclassAccountController:Controller\n{\nprivateUserManager<IdentityUser>_userManager;\nprivateSignInManager<IdentityUser>_signInManager;\n\npublicAccountController(UserManager<IdentityUser>userManager,\nSignInManager<IdentityUser>signInManager)\n{\nthis._userManager=userManager;\nthis._signInManager=signInManager;\n}\n\n[HttpGet]\npublicIActionResultLogin()\n{\nreturnView();\n}\n\n[HttpPost]\npublicasyncTask<IActionResult>Login(LoginViewModelmodel)\n{\nif(ModelState.IsValid)\n{\nvarresult=await_signInManager.PasswordSignInAsync(\nmodel.Email,model.Password,model.RememberMe,false);\n\nif(result.Succeeded)\n{\n\nreturnRedirectToAction(&34;,&34;);\n}\n\nModelState.AddModelError(string.Empty,&34;);\n}\n\nreturnView(model);\n}\n\n}\n}

21.5.4会话Cookie与持久性Cookie

维基百科解释:Cookie并不是它的原意“甜饼”的意思,而是一个保存在客户机中的简单的文本文件,这个文件与特定的Web文档关联在一起,保存了该客户机访问这个Web文档时的信息,当客户机再次访问这个Web文档时这些信息可供该文档使用。由于“Cookie”具有可以保存在客户机上的神奇特性,因此它可以帮助我们实现记录用户个人信息的功能,而这一切都不必使用复杂的CGI等程序。

简单来说,我们把Cookie理解为一个大小不超过4kB,便于我们在客户端保存一些用户个人信息的功能。

在ASP.NETCoreIdentity中,用户成功登录后,将发出Cookie,并将此Cookie随每个请求一起发送到服务器,服务器会解析此Cookie信息来了解用户是否已经通过身份验证和登录。此Cookie可以是会话Cookie或持久Cookie。

会话Cookie是指用户登录成功后,Cookie会被创建并存储在浏览器会话实例中。会话Cookie不包含过期时间,它会在浏览器窗口关闭时被永久删除。

持久Cookie是指用户登录成功后,Cookie会被创建并存储在浏览器中,因为是持久Cookie,所以在关闭浏览器窗口后,它不会被删除。但是,它通常有一个到期时间,会在到期后被删除。

在LoginViewModel.cs视图模型中,我们已经添加了一个bool类型的RememberMe属性。用户可在登录时选择记住我,选中即使用持久性Cookie,而未选中则为会话Cookie。

现在运行项目,我们可以在登录的时候选择记住我,登录成功后如图21.9所示。

图21.9

打开开发者工具(按F12键),观察图21.9框中的内容,可以发现过期时间是很长的。现在关闭浏览器,并将其再次打开,用户也依然是登录状态。这便是持久性Cookie的作用,只有在到期时间到了之后才会删除。

至于会话Cookie验证,我们在登录的时候取消选择记住我,然后看到如图21.10所示的内容。

图21.10

这里已经是一个会话了,它不包含过期时间,在关闭浏览器后,再次将其打开,系统会自动注销用户。

以上就是持久性Cookie与会话Cookie的区别了。

在本章中我们学习了Identity的基本功能,创建一个系统用户并完成了登录注册及状态检查。在后面的章节中,内容会逐步深入,可配合源代码学习。

21.6小结

本章介绍了ASP.NETCoreIdentity框架的定位及作用,并利用它提供的API完成了用户的登录与注销等基本功能。在后面的章节中我们会使用更多的API将系统趋于完善。

本文摘自《深入浅出ASP.NETCore》

这本书原本的计划是描述EFCore中的知识点,带领读者完整地做一个管理系统。但是个人觉得这样写与市场上的其他图书没有什么区别,它就是一本概述知识点的图书,无非多了一个较为完整的功能系统而已。对于我而言这是有落差的。有一天和朋友吃饭,他建议把ABP中那些有效的、目前市场上流行的设计理念整合进图书,不用讲解得太明白,只是告诉读者如何用以及这么用的好处即可。

本书的结构

本书分为以下5个部分。

第一部分(第1章~第9章)介绍ASP.NETCore的基础知识,比如中间件、环境变量和配置信息等,简单讲解完整的ASP.NETCore的项目结构。第二部分(第10章~第20章)介绍并运用MVC模型及路由中间件,结合ASP.NETCore提供的TagHelper等新特性,完成对学生信息的增删改查、图片上传;介绍简单的仓储模式与依赖注入的关系,为搭建管理系统做好基础准备。第三部分(第21章~第29章)通过搭建一个基础管理系统,分析及处理实际业务场景中的常见问题,比如身份验证和授权、客户端及服务端验证、配置信息、EFCore数据访问、数据分页和统一异常处理等。第四部分(第30章~第38章)介绍架构的作用以及意义,根据架构的思想应用设计模式,结合C#泛型特性优化仓储模式,建立多层体系架构,通过并发、LINQ及活用EntityFrameworkCore中的常用功能完成一个类似领域驱动设计的项目。第五部分(第39章~第42章)介绍简单的WebAPI入门、部署ASP.NETCore项目以及从ASP.NETCore2.2到ASP.NETCore3.1的版本升级过程。

OK,本文到此结束,希望对大家有所帮助。

Published by

风君子

独自遨游何稽首 揭天掀地慰生平