这节我们主要介绍ASP.NET Core Identity认证,认证是决定用户是否能够成功登录应用程序的一个过程,用户通过提供自己的用户名和密码来证明他们自己是真实用户,当登录成功时, Identity 认证用户并且赋予访问ASP.NET Core 应用程序安全资源
1、ASP.NET Core Identity如何认证
我们创建ASP.NET Core Identity Authentication特性,允许对Identity User 进行认证,首先我们创建一个HomeController并修改Index Action 返回一个字符串到View
当我们运行应用程序时,我们可以没有任何限制的访问Index action,浏览器发送匿名请求(anonymous request) 到Home Controller 的Index 方法,这个匿名请求能访问应用程序Home Controller资源,因此我们能在浏览器上看到Hello消息
现在我们给Index Action增加认证,注意Identity Authorization和Authentication不同,Authorization在Authentication之后,用户授权是指Identity授权一个用户访问应用程序资源
在Index 方法上使用[Authorize]特性,用户访问Controller之前需要做认证
ASP.NET Core Identity 导航到AccountController 的Login方法,这个是Identity默认登录页面,https://localhost:7296/
2、修改Identity 中默认登录的URL
builder.Services.ConfigureApplicationCookie(opts=> opts.LoginPath = "/Authenticate/Login");3、ASP.NET Core Identity 登录页面
3.1、ASP.NET Core Identity 登录页面
在Models文件夹下创建Login文件,实体类中包含了三个属性,分别为Email、Password、ReturnUrl
public class Login{[][]public string Email { get; set; } = !;[][][]public string Password { get; set; } = !;public string? ReturnUrl { get; set; }}
[]public class AccountController : Controller{private UserManager<AppUser> _userManager;private SignInManager<AppUser> _signInManager;public AccountController(UserManager<AppUser> userManager, SignInManager<AppUser> signInManager){_userManager = userManager;_signInManager = signInManager;}[]public IActionResult Login(string returnUrl){var login = new Login();login.ReturnUrl = returnUrl;return View(login);}[][][]public async Task<IActionResult> Login(Login login){if (ModelState.IsValid){var appUser = await _userManager.FindByEmailAsync(login.Email);if (appUser != ){await _signInManager.SignOutAsync();var signInResult = await _signInManager.PasswordSignInAsync(appUser, login.Password, false, false);if (signInResult.Succeeded){return Redirect(login.ReturnUrl ?? "/");}}}return View(login);}}
private UserManager<AppUser> _userManager;private SignInManager<AppUser> _signInManager;public AccountController(UserManager<AppUser> userManager, SignInManager<AppUser> signInManager){_userManager = userManager;_signInManager = signInManager;}
下面我们添加一个Http Get版本的Login方法,在该方法上使用[AllowAnonymous] 特性,可以匿名访问该方法,否则用户不能登录,这个action方法接受一个returnUrl的参数,该参数提供查询字符串,背后的原理:模型绑定将自动绑定该URL变量
[]public IActionResult Login(string returnUrl){var login = new Login();login.ReturnUrl = returnUrl;return View(login);}
[][][]public async Task<IActionResult> Login(Login login){if (ModelState.IsValid){var appUser = await _userManager.FindByEmailAsync(login.Email);if (appUser != ){await _signInManager.SignOutAsync();var signInResult = await _signInManager.PasswordSignInAsync(appUser, login.Password, false, false);if (signInResult.Succeeded){return Redirect(login.ReturnUrl ?? "/");}}}return View(login);}
[AllowAnonymous] 表示允许匿名用户访问 [ValidateAntiForgeryToken] 阻止CSRF攻击
首先我们根据UserManager 的 FindByEmailAsync()方法获取到用户信息,如果用户信息不为空,我们先退出登录,然后再调用PasswordSignInAsync 进行登录,这个方法第三个参数和第四个参数分别设置成false,第三个参数表示我们不想持久化Cookie,第四个参数表示用户登录失败时是否锁定用户,该方法返回SignInResult 登录结果对象,如果成功Succeeded返回true,否则返回false,登录成功之后,跳转到客户指定的URL
我们需要创建一个Login View的登录表单,这个视图是Identity登录页面,处理用户账户登录过程,我们在Views/Account 下创建View页面,代码如下:
@model Login@{ViewData["Title"] = "Login";}<div class="text-danger" asp-validation-summary="All"></div><form class="form-horizontal" role="form" method="post"><div class="mb-3 row"><label asp-for="Email" class="col-sm-1 control-label"></label><div class="col-sm-11"><input asp-for="Email" class="form-control" /></div></div><div class="mb-3 row"><label asp-for="Password" class="col-sm-1 control-label"></label><div class="col-sm-11"><input asp-for="Password" class="form-control" /></div></div><div class="mb-3 row"><div class="col-sm-11 offset-sm-1"><button type="submit" class="btn btn-primary">登录</button></div></div></form>
我们可以使用UserManager<T>的GetUserAsyns()方法类获取当前登录的用户信息并显示在View上:
[]public async Task<IActionResult> Index(){var appUser = await _userManager.GetUserAsync(HttpContext.User);var message = "Hello " + appUser?.UserName;return View((object)message);}
4、ASP.NET Core Identity 退出页面
public async Task<IActionResult> Logout(){await _signInManager.SignOutAsync();return RedirectToAction("Index", "Home");}
ASP.NET Core Identity使用Cookie确定一个用户是否被认证,一旦这个用户被认证Cookie就会被创建并且存储在浏览器,每次HTTP请求时都会发送Cookie到服务器,当我们在浏览器中打开应用程序的任何URL,Identity就能确定请求来自哪个用户,Cookie名字为.AspNetCore.Identity.Application,我们可以在浏览器中查看到这个Cookie
Cookie方法设置ASP.NET Core Identity Cookie超时时间
builder.Services.ConfigureApplicationCookie(opts =>{opts.LoginPath = "/Account/Login";//设置Cookie名称opts.Cookie.Name = ".AspNetCore.Identity.Application";//设置Cookie超时时间opts.ExpireTimeSpan = TimeSpan.FromMinutes(20);//设置滑动时间opts.SlidingExpiration = true;});
ASP.NET Core Identity Remember Me
我们创建一个Remember Me功能,帮助客户记住密码,我们只需要登录一次,Identity将创建一个持久Cookie在浏览器,我们在login.cshtml的页面添加一个type=checkbox的输入框
@model Login@{ViewData["Title"] = "Login";}<div class="text-danger" asp-validation-summary="All"></div><form class="form-horizontal" role="form" method="post"><div class="mb-3 row"><label asp-for="Email" class="col-sm-1 control-label"></label><div class="col-sm-11"><input asp-for="Email" class="form-control" /></div></div><div class="mb-3 row"><label asp-for="Password" class="col-sm-1 control-label"></label><div class="col-sm-11"><input asp-for="Password" class="form-control" /></div></div><div class="mb-3 row"><label asp-for="RememberMe" class="col-sm-1 control-label"></label><div class="col-sm-11"><input type="checkbox" asp-for="RememberMe" /></div></div><div class="mb-3 row"><div class="col-sm-11 offset-sm-1"><button type="submit" class="btn btn-primary">登录</button></div></div></form>
并在Login实体类中增加属性:
public class Login{[][]public string Email { get; set; } = !;[][][]public string Password { get; set; } = !;public string? ReturnUrl { get; set; }[][]public bool RememberMe { get; set; }}
修改Login登录方法
[][][]public async Task<IActionResult> Login(Login login){if (ModelState.IsValid){var appUser = await _userManager.FindByEmailAsync(login.Email);if (appUser != ){await _signInManager.SignOutAsync();var signInResult = await _signInManager.PasswordSignInAsync(appUser, login.Password,login.RememberMe, false);if (signInResult.Succeeded){return Redirect(login.ReturnUrl ?? "/");}}ModelState.AddModelError(nameof(login.Email),"Login Failed: Invalid Email or password");}return View(login);}
源代码地址:
https://github.com/bingbing-gui/Asp.Net-Core-Skill/tree/master/AspNetCore.Identity/Identity
补充:ASP.NET Core Identity 系列之三 源代码地址以废弃,上面那是最新地址
