十二、ASP.NET Core 认证
安全性对于所有类型的应用都是至关重要的,包括 web 应用。 如果有人可以冒充你来更新你的状态,你还会使用 Facebook 吗? 如果这是可能的,那么没有人会再回到 Facebook。 从这个示例中,我们可以看到,安全性与其说是一种特性,不如说是所有应用的必要特性。
在本章中,我们将学习以下主题:
- 身份验证和授权
- ASP。 净的身份
- 如何在 ASP 中实现安全性。 asp.NET Core 应用使用.NET 身份与实体框架
当我们讨论应用的安全性时,我们主要希望防止任何未经授权的访问,这意味着只有访问信息的人才能够访问它——不多也不多。
在进一步讨论之前,我想澄清一些关于安全性的核心概念。
认证
身份验证是验证用户是否有权访问系统的过程。 在任何应用中,都将首先对用户进行身份验证。 这可以通过要求用户输入他们的用户 ID 和密码来实现。
授权
授权是验证用户是否有权访问所请求的资源的过程。 他们可能拥有对系统的合法访问权,但他们可能没有访问请求的资源的权限,因为他们没有必需的访问权。 例如,只有管理员用户可以访问应用的配置页面,而普通用户不应该被允许使用该页面。
ASP.NET Identity 为保护应用提供了几个特性。
让我们考虑以下简单场景,其中用户试图访问安全页面,该页面只有经过授权的人员才能访问。 由于用户没有登录,它们将被重定向到登录页面,以便我们可以对用户进行身份验证和授权。 认证成功后,用户将被重定向到安全页面。 如果由于任何原因,我们不能对用户进行身份验证和授权,我们可以将他们重定向到“拒绝访问”页面:
ASP.NET Core Identity 是一个会员系统,它使您能够轻松地保护应用,并且具有向应用添加登录功能等特性。 以下是使用ASP 需要遵循的步骤.NET Identity(使用实体框架)
- 将相关依赖项添加到
project.json
文件中。 - 创建一个
appsettings.json
文件并存储数据库连接字符串。 - 创建一个
ApplicationUser
类和ApplicationDbContext
类。 - 配置应用以使用 ASP。 净的身份。
- 创建用于注册和登录的 ViewModels。
- 创建必要的控制器和关联的操作方法和视图。
向项目中添加相关的依赖项。 json 文件
如果你想使用 ASP.NET Identity with Entity Framework 在你的应用中,你需要添加以下依赖:
"EntityFramework.Commands": "7.0.0-rc1-final",
"EntityFramework.MicrosoftSqlServer": "7.0.0-rc1-final",
"Microsoft.AspNet.Authentication.Cookies": "1.0.0-rc1-final",
创建一个appsettings.json
文件并存储数据库连接字符串。
在项目的根级别创建一个名为appsettings.json
的文件,如下截图所示:
将以下连接字符串存储在appsettings.json
中。 这个连接字符串将被 ASP.NET Identity 将数据存储在相关的表中:
{
"Data": {
"DefaultConnection": {
"ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=aspnet_security;Trusted_Connection=True;MultipleActiveResultSets=true"
}
}
}
添加 ApplicationUser 和 ApplicationDbContext 类
创建一个Models文件夹和两个文件——ApplicationDbContext.cs和ApplicationUser.cs -,如下截图所示:
ApplicationUser
类继承自IdentityUser
类(在AspNet.Identity.EntityFramework6
命名空间中可用),如下所示:
public class ApplicationUser : IdentityUser
{
..
}
您可以根据应用的需要向用户添加属性。 我没有添加任何属性,因为我想保持事情简单,以显示 ASP 的功能。 净的身份。
ApplicationDbContext
类继承自ApplicationUser
的IdentityDbContext
类。 在构造函数方法中,传递connectionstring
,最终传递给基类。
甚至OnModelCreating
方法也被覆盖了。 如果你想改变任何表名(由 Identity 生成),你可以这样做:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext(string nameOrConnectionString) : base(nameOrConnectionString) { }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
}
}
创建Models
文件之后,需要配置应用和服务。 您可以在Configure
和ConfigureServices
中配置这些,它们在Startup
类中找到。
配置应用使用身份
为了使用 Identity,我们只需要在Startup
类的Configure
方法中添加以下一行:
app.UseIdentity();
完整的Configure
方法如下所示,同时调用UseIdentity
方法,即app.UseIdentity()
:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
if (env.IsDevelopment())
{
app.UseBrowserLink();
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseIISPlatformHandler(options => options.AuthenticationDescriptions.Clear());
app.UseStaticFiles();
app.UseIdentity();
// To configure external authentication please see http://go.microsoft.com/fwlink/?LinkID=532715
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
在ConfigureServices
方法中,我们将做以下改动:
- 我们将使用从
appsettings.json
文件获取的连接字符串添加ApplicationDbContext
类 - 我们将添加身份与
UserStore
和RoleStore
-
最后,我们将问 ASP.NET Core 返回
AuthMessageSender
每当我们请求IEmailSender
和ISMSSender
类``` public void ConfigureServices(IServiceCollection services { // Add framework services.
services.AddScoped<ApplicationDbContext>(f => { return new ApplicationDbContext(Configuration["Data:DefaultConnection:ConnectionString"]); }); services.AddIdentity<ApplicationUser, IdentityRole>() .AddUserStore<UserStore<ApplicationUser, ApplicationDbContext>>() .AddRoleStore<RoleStore<ApplicationDbContext>>() .AddDefaultTokenProviders(); services.AddMvc(); // Add application services. services.AddTransient<IEmailSender, AuthMessageSender>(); services.AddTransient<ISmsSender, AuthMessageSender>(); }
```
创建视图模型
接下来,我们将创建几个 viewmodel,它们将在我们的 Views 模型中使用。
首先,我们将创建一个包含三个属性——Email
、Password
和ConfirmPassword
的RegisterViewModel
类。 我们用适当的属性装饰属性,这样我们就可以使用一个不引人注目的 jQuery 验证来使用客户端验证。 我们将所有字段的要求如下:
public class RegisterViewModel
{
[Required]
[EmailAddress]
[Display(Name = "Email")]
public string Email { get; set; }
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
}
现在,我们可以创建LoginViewModel model
,用户可以使用它登录到您的应用。 还有一个额外的属性RememberMe
,勾选该属性后,您无需再次输入密码即可登录:
public class LoginViewModel
{
[Required]
[EmailAddress]
public string Email { get; set; }
[Required]
[DataType(DataType.Password)]
public string Password { get; set; }
[Display(Name = "Remember me?")]
public bool RememberMe { get; set; }
}
创建控制器和关联的操作方法
现在我们需要创建一个AccountController
类,在其中我们将定义用于身份验证和授权的操作方法:
public class AccountController : Controller
{
private readonly UserManager<ApplicationUser> _userManager;
private readonly SignInManager<ApplicationUser> _signInManager;
private readonly IEmailSender _emailSender;
private readonly ISmsSender _smsSender;
private readonly ILogger _logger;
public AccountController(
UserManager<ApplicationUser> userManager,
SignInManager<ApplicationUser> signInManager,
IEmailSender emailSender,
ISmsSender smsSender,
ILoggerFactory loggerFactory)
{
_userManager = userManager;
_signInManager = signInManager;
_emailSender = emailSender;
_smsSender = smsSender;
_logger = loggerFactory.CreateLogger<AccountController>();
}
}
在前面的代码中,我们使用由不同组件提供的服务。 UserManager
和SignInManager
由 ASP 提供。 净的身份。 IEmailSender
和ISmsSender
是我们编写的用于发送电子邮件和短信的自定义类。 我们将在本章后面更多地讨论电子邮件和 SMS。 日志记录是由 Microsoft Logging 扩展提供的。 下面是一个简单的登录HTTPGET
方法。 它只是存储从Login
方法访问的 URL,并返回登录页面:
[HttpGet]
[AllowAnonymous]
public IActionResult Login(string returnUrl = null)
{
ViewData["ReturnUrl"] = returnUrl;
return View();
}
创建视图
现在,我们将为登录创建各自的 View 页面。 在这个视图页面中,我们只显示以下细节:
@using System.Collections.Generic
@using Microsoft.AspNet.Http
@using Microsoft.AspNet.Http.Authentication
@using AspNet.Identity.EntityFramework6
@model LoginViewModel
@inject SignInManager<ApplicationUser> SignInManager
@{
ViewData["Title"] = "Log in";
}
<h2>@ViewData["Title"].</h2>
<div class="row">
<div class="col-md-8">
<section>
<form asp-controller="Account" asp-action="Login" asp-route-returnurl="@ViewData["ReturnUrl"]" method="post" class="form-horizontal" role="form">
<h4>Use a local account to log in.</h4>
<hr />
<div asp-validation-summary="ValidationSummary.All" class="text-danger"></div>
<div class="form-group">
<label asp-for="Email" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="Email" class="form-control" />
<span asp-validation-for="Email" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<label asp-for="Password" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="Password" class="form-control" />
<span asp-validation-for="Password" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<div class="checkbox">
<input asp-for="RememberMe" />
<label asp-for="RememberMe"></label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<button type="submit" class="btn btn-default">Log in</button>
</div>
</div>
<p>
<a asp-action="Register">Register as a new user?</a>
</p>
<p>
<a asp-action="ForgotPassword">Forgot your password?</a>
</p>
</form>
</section>
</div>
</div>
@section Scripts {
@{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
}
当用户第一次登录到应用时,他们可能没有任何登录凭据,因此我们的应用应该提供一个特性,用户可以使用它为自己创建登录。 我们将创建一个简单的Register
操作方法,它将返回一个用户可以注册自己的视图:
[HttpGet]
[AllowAnonymous]
public IActionResult Register()
{
return View();
}
我们还将创建相应的 View,其中包含电子邮件、密码、密码确认和Register
按钮的输入控件:
@model RegisterViewModel
@{
ViewData["Title"] = "Register";
}
<h2>@ViewData["Title"].</h2>
<form asp-controller="Account" asp-action="Register" method="post" class="form-horizontal" role="form">
<h4>Create a new account.</h4>
<hr />
<div asp-validation-summary="ValidationSummary.All" class="text-danger"></div>
<div class="form-group">
<label asp-for="Email" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="Email" class="form-control" />
<span asp-validation-for="Email" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<label asp-for="Password" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="Password" class="form-control" />
<span asp-validation-for="Password" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<label asp-for="ConfirmPassword" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="ConfirmPassword" class="form-control" />
<span asp-validation-for="ConfirmPassword" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<button type="submit" class="btn btn-default">Register</button>
</div>
</div>
</form>
@section Scripts {
@{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
}
以下是对应的POST
动作注册方法。 这里,程序检查模型是否有效,如果有效,它将使用模型数据创建一个ApplicationUser
对象,并调用 Identity API(CreateAsync
方法)。 如果可以创建user
变量,则用户将使用该用户 ID 登录,并被重定向到Home
页面:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
var result = await _userManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await _signInManager.SignInAsync(user, isPersistent: false);
return RedirectToAction(nameof(HomeController.Index), "Home");
}
AddErrors(result);
}
return View(model);
}
登出功能非常简单。 它只需要调用 Identity API 的SignoutAsync
方法,并被重定向到Index
页面:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> LogOff()
{
await _signInManager.SignOutAsync();
_logger.LogInformation(4, "User logged out.");
return RedirectToAction(nameof(HomeController.Index), "Home");
}
回到登录功能,下面是各自的操作方法。 我们正在调用 Identity API 的PasswordSignInAsync
方法。 成功登录后,我们将访问登录功能的 URL 重定向:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
{
ViewData["ReturnUrl"] = returnUrl;
if (ModelState.IsValid)
{
var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: false);
if (result.Succeeded)
{
return RedirectToLocal(returnUrl);
}
}
// If there is any error, display the form again
return View(model);
}
电子邮件和短信服务
如果你想将电子邮件和短信服务添加到你的应用的身份验证功能中,你可以通过创建如下所示的接口和类来实现:
public interface IEmailSender
{
Task SendEmailAsync(string email, string subject, string message)
}
public interface ISmsSender
{
Task SendSmsAsync(string number, string message);
}
public class AuthMessageSender : IEmailSender, ISmsSender
{
public Task SendEmailAsync(string email, string subject, string message)
{
// We can plug in our email service here to send an email.
return Task.FromResult(0);
}
public Task SendSmsAsync(string number, string message)
{
// We can plug in our SMS service here to send a text message.
return Task.FromResult(0);
}
}
在控制器中固定操作方法
为了便于解释,让我们假设About页面是一个安全页面,只有经过身份验证的用户才能访问它。
我们只需要用[Authorize]
属性装饰Home
控制器中的About
动作方法:
[Authorize]
public IActionResult About()
{
ViewData["Message"] = "This is my about page";
return View();
}
当用户试图访问登录页面而不登录应用时,进行上述更改将把用户重定向到登录页面:
在下面的屏幕截图中,您将注意到 URL 中有一个额外的查询参数ReturnURL,
。 这个ReturnURL
参数将应用重定向到该特定的页面(在本例中,通过ReturnURL
参数—Home/About传递的值)。
一旦您登录,您将被重定向到您先前请求的页面:
当您注册一个新用户时,用户的详细信息将存储在由 ASP 创建的相关表中。 净的身份。
打开 SQL Server 对象管理器窗口,选择View|SQL Server 对象管理器,如下图所示:
一旦您选择SQL Server 对象管理器选项,您将看到一个类似如下截图的窗口。 ASP.NET Identity 使用实体框架和前面在appsettings.json
包中提供的连接字符串为我们创建数据库。
ASP.NET Identity 创建几个表来维护与身份相关的信息和实体框架的数据库迁移历史。 因为我们使用 ASP.NET 身份在基本级别上,除了dbo 之外,没有任何与身份相关的表会被填充。 AspNetUsers.:
您可以右键单击dbo。 AspNetUsers表,选择View Data查看数据:
由于在我们的应用中只注册了一个用户,所以只创建了一行。 请注意,散列密码(由 ASP 标记.NET Identity 为我们),并且表中不会存储空白密码。
总结
在本章中,我们学习了身份验证和授权。 我们还学习了如何实现 ASP。 asp.net 标识.NET Core 应用,遵循一个循序渐进的过程。 我们还讨论了 ASP 中涉及到的表.NET 身份,并学习了如何查看由 asp.net 创建的数据。 净的身份。
版权属于:月萌API www.moonapi.com,转载请注明出处