asp.net core 系列之用户认证(authentication)
ASP.NET Core 的 identity 是一种需要用户登录的会员系统,用户可以创建一个登录信息存储在 Identity 的的账号,
或者也可以使用第三方登录,支持的第三方登录包括:Facebook, Google, Microsoft Account, and Twitter.
Identity 使用Sql Server 存储用户的姓名,密码等数据,当然你也可以选择其他的存储工具进行存储
这篇教程,将会讲解如何使用Identity进行用户的注册,登录,登出
1.创建一个带认证(authentication)的web应用
- 文件->新建->项目
- 选择ASP.NET Core Web 应用程序,命名WebApp1 ,点击确定
- 然后选择web 应用程序,然后更改身份验证
- 选择个人用户账号,确定
生成的项目会提供 ASP.NET Core Identity 功能,并且 Identity area 会暴露 下面几个 终端(endpoint):
- /Identity/Account/Login
- /Identity/Account/Logout
- /Identity/Account/Manage
2.迁移
观察生成的代码,发现migration已经生成了,只需要更新到数据库
在nuget 程序控制台中,输入:
Update-Database
直接在vs中的视图,打开sql server 对象管理器,查看数据库效果,确认数据库更新成功:
3.配置 Identity 服务(Identity service)
服务被添加到了StartUp下的 ConfigureServices方法中
public void ConfigureServices(IServiceCollection services) { services.Configure<CookiePolicyOptions>(options => { options.CheckConsentNeeded = context => true; options.MinimumSameSitePolicy = SameSiteMode.None; }); services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer( Configuration.GetConnectionString("DefaultConnection"))); services.AddDefaultIdentity<IdentityUser>() .AddDefaultUI(UIFramework.Bootstrap4) .AddEntityFrameworkStores<ApplicationDbContext>();
//这里对Identity做一些配置 services.Configure<IdentityOptions>(options => { // Password settings.密码配置 options.Password.RequireDigit = true; options.Password.RequireLowercase = true; options.Password.RequireNonAlphanumeric = true; options.Password.RequireUppercase = true; options.Password.RequiredLength = 6; options.Password.RequiredUniqueChars = 1; // Lockout settings.锁定设置 options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5); options.Lockout.MaxFailedAccessAttempts = 5; options.Lockout.AllowedForNewUsers = true; // User settings.用户设置 options.User.AllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+"; options.User.RequireUniqueEmail = false; }); services.ConfigureApplicationCookie(options => { // Cookie settings 缓存设置 options.Cookie.HttpOnly = true; options.ExpireTimeSpan = TimeSpan.FromMinutes(5); options.LoginPath = "/Identity/Account/Login"; options.AccessDeniedPath = "/Identity/Account/AccessDenied"; options.SlidingExpiration = true; }); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); }
4.添加 注册,登录,登录功能
- 在解决方案的项目上,右键添加->新搭建基架的项目
- 选择标识,添加
- 然后选择你想添加的项
这里的数据上下文中需要选中一个数据的,注意
之后,会生成相应的一些文件,包括注册,登录,登出
5.现在再看下,生成的代码
注册
public async Task<IActionResult> OnPostAsync(string returnUrl = null) { returnUrl = returnUrl ?? Url.Content("~/"); if (ModelState.IsValid) { var user = new IdentityUser { UserName = Input.Email, Email = Input.Email }; var result = await _userManager.CreateAsync(user, Input.Password); //创建账户
if (result.Succeeded) { _logger.LogInformation("User created a new account with password."); var code = await _userManager.GenerateEmailConfirmationTokenAsync(user); //生成邮箱验证码 var callbackUrl = Url.Page( //生成验证的回调地址 "/Account/ConfirmEmail", pageHandler: null, values: new { userId = user.Id, code = code }, protocol: Request.Scheme); await _emailSender.SendEmailAsync(Input.Email, "Confirm your email", //发送邮箱验证邮件 $"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>."); await _signInManager.SignInAsync(user, isPersistent: false); //登录 return LocalRedirect(returnUrl); } foreach (var error in result.Errors) { ModelState.AddModelError(string.Empty, error.Description); } } // If we got this far, something failed, redisplay form return Page(); }
创建成功后,会直接显示登录状态
登录
public async Task<IActionResult> OnPostAsync(string returnUrl = null) { returnUrl = returnUrl ?? Url.Content("~/"); if (ModelState.IsValid) { // This doesn't count login failures towards account lockout // To enable password failures to trigger account lockout, // set lockoutOnFailure: true var result = await _signInManager.PasswordSignInAsync(Input.Email, //密码登录 Input.Password, Input.RememberMe, lockoutOnFailure: true); if (result.Succeeded) //登录成功 { _logger.LogInformation("User logged in."); return LocalRedirect(returnUrl); } if (result.RequiresTwoFactor) //两步验证 { return RedirectToPage("./LoginWith2fa", new { ReturnUrl = returnUrl, RememberMe = Input.RememberMe }); } if (result.IsLockedOut) //锁定 { _logger.LogWarning("User account locked out."); return RedirectToPage("./Lockout"); } else { ModelState.AddModelError(string.Empty, "Invalid login attempt."); return Page(); } } // If we got this far, something failed, redisplay form return Page(); }
登出
public async Task<IActionResult> OnPost(string returnUrl = null) { await _signInManager.SignOutAsync(); //登出 _logger.LogInformation("User logged out."); if (returnUrl != null) { return LocalRedirect(returnUrl); } else { return Page(); } }
登录页面
@using Microsoft.AspNetCore.Identity @inject SignInManager<IdentityUser> SignInManager @inject UserManager<IdentityUser> UserManager <ul class="navbar-nav"> @if (SignInManager.IsSignedIn(User)) { <li class="nav-item"> <a class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Manage/Index" title="Manage">Hello@User.Identity.Name!</a> </li> <li class="nav-item"> <form class="form-inline" asp-area="Identity" asp-page="/Account/Logout" asp-route-returnUrl="@Url.Page("/", new { area = "" })" method="post"> <button type="submit" class="nav-link btn btn-link text-dark">Logout</button> </form> </li> } else { <li class="nav-item"> <a class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Register">Register</a> </li> <li class="nav-item"> <a class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Login">Login</a> </li> } </ul>
6.验证Identity
默认的web项目模板允许匿名访问到主页的,为了验证Identity,给Privacy 页面增加 [Authorize]
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc.RazorPages; namespace WebApp1.Pages {
[Authorize] public class PrivacyModel : PageModel { public void OnGet() { } } }
7.运行
测试注册,登录,登出功能
以及认证效果对比(即Privacy页面增加Authrize前后):
加之前:不需要登录,即可访问Privacy页面
加之后:需要登录,才能访问此页面
这里先记录添加Identity操作流程,之后会具体讲解一些功能点