本文源代码获取:文末
启动一个新项目并从头开始处理身份验证和授权可能会筋疲力尽。它通常涉及创建登录和注册功能,这可能很耗时。管理刷新令牌和实现双因素身份验证等挑战增加了复杂性。
值得庆幸的是,随着 .NET 8 的到来,这些任务大大简化,只需要最少的配置。
在本文中,我将指导你完成各种标识配置方案,包括:
基本注册和登录。
使用持有者令牌保护终结点。
检索用户信息。
电子邮件确认。
重新发送电子邮件确认。
更改默认设置并添加自定义用户属性。
配置双因素身份验证 (MVC)。
先决条件:.NET 8 或更高版本。
在继续之前,让我概述一下我当前的环境设置:
.NET Web API 应用程序。
Visual Studio 2022 年。
利用SQLite模拟真实数据库,而不是内存数据库。
接下来,让我们安装必要的 NuGet 包。
dotnet add package Microsoft.AspNetCore.Identity.EntityFrameworkCore
dotnet add package Microsoft.EntityFrameworkCore.Design
dotnet add package Microsoft.EntityFrameworkCore.Sqlite
dotnet add package Microsoft.EntityFrameworkCore.Tools
基本注册和登录。
首先,首先创建所有身份生成的表的存储位置。
// IdentityUser is the Microsoft base identity class.
// creates empty scheme with just all the identity tables.
class AppDbContext : IdentityDbContext<IdentityUser>
{
public AppDbContext(DbContextOptions options) : base(options)
{
}
}
接下来,我们将注册身份验证和授权中间件,从而灵活地在持有者令牌或 Cookie 之间进行选择。在此示例中,我们将选择持有者令牌,以便于在登录时检索持有者令牌。
// Program.cs
builder.Services.AddAuthentication()
.AddBearerToken(IdentityConstants.BearerScheme);
builder.Services.AddAuthorizationBuilder();
之后,我们将注册我们的 ,在此示例中,它是一个 SQLite 数据库。
// Program.cs
builder.Services.AddDbContext<AppDbContext>(options =>
{
options.UseSqlite("DataSource=app.db");
});
之后,我们需要将 作为身份存储连接,以便所有操作都指向 SQLite 数据库。
// Program.cs
builder.Services.AddIdentityCore\<IdentityUser>()
.AddEntityFrameworkStores\<AppDbContext>()
.AddApiEndpoints();
最后,我们需要将所有端点添加为应用程序端点的一部分。这可以通过在构建生成器后映射标识终结点来实现。
app.MapIdentityApi<IdentityUser>();
您的Program.cs文件现在应类似于此结构。
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddAuthentication()
.AddBearerToken(IdentityConstants.BearerScheme);
builder.Services.AddAuthorizationBuilder();
builder.Services.AddDbContext<AppDbContext>(options =>
{
options.UseSqlite("DataSource=app.db");
});
builder.Services.AddIdentityCore<IdentityUser>()
.AddEntityFrameworkStores<AppDbContext>()
.AddApiEndpoints();
var app = builder.Build();
app.MapIdentityApi<IdentityUser>();
app.UseSwagger();
app.UseSwaggerUI();
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
在运行应用程序之前,请不要忘记添加新的迁移,并通过从包管理器控制台执行以下命令来更新数据库。
Add-Migration initial
Update-Database
现在,运行应用程序并打开 Swagger。您应该会看到自动生成的终结点集合。
生成的身份终结点。
尝试注册新用户。如果尝试使用无效的电子邮件地址或不符合条件的密码创建新用户,则标识将返回错误以及发生的具体详细信息。
现在,让我们继续登录过程。如果提供的电子邮件或密码无效,则身份将返回 401 未授权状态。
使用持有者令牌保护终结点。
将身份验证配置为返回持有者令牌后,我们需要将此持有者令牌用于任何需要授权的受保护终结点。
必须注意的是,生成的令牌不是标准的 JSON Web 令牌 (JWT)。此决定是有意为之的,因为内置标识主要用于简单方案。令牌选项并不意味着充当功能齐全的身份服务提供商或令牌服务器,而是无法使用 cookie 的客户端的 cookie 选项的替代方案。
现在,让我们尝试访问授权端点,特别是 /manage/info 端点。如果您尝试从 Swagger 访问它,它将显示未经授权的错误。接下来,使用 Postman 登录,保存 accessToken,并在调用 /manage/info 端点时包含它。这一次,它应该返回所需的结果。
检索用户信息
要随时检索当前登录用户的信息,请使用存储当前登录用户信息的类。ClaimsPrincipal
要使用最小 API 方法实现此目的,请执行以下操作:
app.Map("/", (ClaimsPrincipal user) => $"Hello {user.Identity!.Name}")
.RequireAuthorization();
对于控制器方法:
[ApiController]
[Route("[controller]")]
public class TestController: ControllerBase
{
[HttpGet]
[Authorize]
public string Get()
{
return User.Identity!.Name;
}
}
请务必注意,上述示例使用“**!”**运算符,这意味着标识应始终存在,而不可能为 null。此假设成立,因为两者都是需要事先登录的授权端点。但是,建议验证标识是否存在,以防止潜在的 null 引用异常。
电子邮件确认
Microsoft建议使用SendGrid或其他电子邮件服务发送电子邮件,而不是SMTP。SMTP 很难保护和正确设置。
在本教程中,SendGrid 用于发送电子邮件。发送电子邮件需要 SendGrid 帐户和密钥。请参阅免费开始使用 SendGrid,注册免费的 SendGrid 帐户。
1- 在文件中配置 SendGrid 所需信息。避免将这些设置直接添加到appsettings.json文件中,以降低安全风险。secrets.json
{
"SendGridKey": "your send-grid key",
"From": "your registered email",
"Name": "your registered name"
}
注册电子邮件和姓名
SendGrid API 密钥
2- 安装必要的 NuGet 包。
dotnet add package SendGrid
dotnet add package SendGrid.Extensions.DependencyInjection
3-实现IEmailSender
要实现,请使用类似于以下内容的代码进行创建:IEmailSenderEmailSender.cs
using Microsoft.AspNetCore.Identity.UI.Services;
using SendGrid;
using SendGrid.Helpers.Mail;
namespace Identity;
public class EmailSender : IEmailSender
{
private readonly ILogger _logger;
private readonly IConfiguration _configuration;
public EmailSender(IConfiguration configuration, ILogger<EmailSender> logger)
{
_configuration = configuration;
_logger = logger;
}
public async Task SendEmailAsync(string toEmail, string subject, string message)
{
var sendGridKey = _configuration["SendGridKey"];
ArgumentNullException.ThrowIfNullOrEmpty(sendGridKey, nameof(sendGridKey));
await Execute(sendGridKey, subject, message, toEmail);
}
public async Task Execute(string apiKey, string subject, string message, string toEmail)
{
var client = new SendGridClient(apiKey);
var msg = new SendGridMessage()
{
From = new EmailAddress(_configuration["From"], _configuration["Name"]),
Subject = subject,
PlainTextContent = message,
HtmlContent = message
};
msg.AddTo(new EmailAddress(toEmail));
// Disable click tracking.
// See https://sendgrid.com/docs/User_Guide/Settings/tracking.html
msg.SetClickTracking(false, false);
var response = await client.SendEmailAsync(msg);
_logger.LogInformation(response.IsSuccessStatusCode
? $"Email to {toEmail} queued successfully!"
: $"Failure Email to {toEmail}");
}
}
4- 将 EmailService 注入其中以启用其使用。Program.cs
// Program.cs
builder.Services.AddTransient<IEmailSender, EmailSender>();
5- 强制登录确认并集成 SendGrid 服务。
现在,如果您尝试再次注册,它将起作用,但您会注意到没有发送电子邮件确认。此外,用户无需任何确认即可登录。
为了解决这个问题并确保正确的流程,我们需要首先在签名过程中要求电子邮件确认。然后,我们需要集成 SendGrid 服务,以便标识框架可以利用它。
// Program.cs
builder.Services.AddIdentityCore<IdentityUser>(options =>
{
options.SignIn.RequireConfirmedEmail = true;
})
builder.Services.AddSendGrid(options =>
options.ApiKey = builder.Configuration["SendGridKey"]!
);
您的文件现在应类似于此结构。Program.cs
using Identity;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.EntityFrameworkCore;
using SendGrid.Extensions.DependencyInjection;
using System.Security.Claims;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddAuthentication()
.AddBearerToken(IdentityConstants.BearerScheme);
builder.Services.AddSendGrid(options =>
options.ApiKey = builder.Configuration["SendGridKey"]!
);
builder.Services.AddTransient<IEmailSender, EmailSender>();
builder.Services.AddAuthorizationBuilder();
builder.Services.AddDbContext<AppDbContext>(options =>
{
options.UseSqlite("DataSource=app.db");
});
builder.Services.AddIdentityCore<IdentityUser>(options =>
{
options.SignIn.RequireConfirmedEmail = true;
})
.AddEntityFrameworkStores<AppDbContext>()
.AddApiEndpoints();
var app = builder.Build();
app.MapIdentityApi<IdentityUser>();
app.Map("/", (ClaimsPrincipal user) => $"Hello {user.Identity!.Name} from minimal apis.")
.RequireAuthorization();
app.UseSwagger();
app.UseSwaggerUI();
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
现在,是时候测试我们的应用程序了。尝试注册一个新用户,并检查您的电子邮件以获取确认链接。单击该链接应将数据库中的确认状态更改为 TRUE。
请记住检查您的垃圾邮件文件夹,因为电子邮件通常最终会在那里。此外,请注意,电子邮件在发送之前会排队,因此预计会有几秒钟的轻微延迟。
注册新用户
Visual Studio 日志
在数据库中创建的用户
确认链接电子邮件
通过单击链接“单击此处”,它应该将您重定向回 localhost,并将用户在数据库中的确认状态更新为 TRUE。
确认消息
确认状态更改为 TRUE
最后,通过注入 SendGrid 服务,我们可以简化 EmailService,从而减少代码行数。
这是该版本的更新版本,可以有效处理所有测试方案。EmailService
using Microsoft.AspNetCore.Identity.UI.Services;
using SendGrid;
using SendGrid.Helpers.Mail;
public class EmailSender : IEmailSender
{
private readonly ILogger _logger;
private readonly IConfiguration _configuration;
private readonly ISendGridClient _sendGridClient;
public EmailSender(IConfiguration configuration, ILogger<EmailSender> logger, ISendGridClient sendGridClient)
{
_configuration = configuration;
_logger = logger;
_sendGridClient = sendGridClient;
}
public async Task SendEmailAsync(string toEmail, string subject, string message)
{
var msg = new SendGridMessage()
{
From = new EmailAddress(_configuration["From"], _configuration["Name"\]),
Subject = subject,
PlainTextContent = message,
HtmlContent = message
};
msg.AddTo(new EmailAddress(toEmail));
var response = await _sendGridClient.SendEmailAsync(msg);
_logger.LogInformation(response.IsSuccessStatusCode
? $"Email to {toEmail} queued successfully!"
: $"Failure Email to {toEmail}");
}
}
重新发送电子邮件确认
您当然需要重新发送确认电子邮件的选项,这对任何应用程序都至关重要。.NET 8 Identity 提供重新发送确认终结点:只需调用并设置正文,如下所示:.NET 8 Identity provides a resend confirmation endpoint: just call and set the body as follows:/resendConfirmationEmail
{
"Email": "user email"
}
更改默认设置并添加自定义用户属性
Microsoft 标识还提供修改默认设置或引入新的自定义属性的功能。
调整默认设置。
builder.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;
});
将新的自定义属性添加到用户属性中。这可以通过创建一个新的用户类来实现,该类继承自 。
class AppUser : IdentityUser
{
public int MyProperty { get; set; }
}
随后,需要添加新的迁移,并且应将新属性集成到表中。
请记住将应用程序中出现的每个项更新为IdentityUserAppUser
配置双因素身份验证 (MVC)
在我们开始之前,这里有一些概念,在我们开始之前最好知道。
什么是多重身份验证 (MFA)?
多重身份验证 (MFA) 通过要求用户在登录过程中提供其他形式的身份标识来增强安全性。这可能包括从手机输入代码、使用 FIDO2 密钥或提供指纹扫描。通过要求第二种形式的身份验证,MFA 使攻击者更难获得未经授权的访问,因为附加因素不容易获得或复制。
什么是双因素身份验证 (2FA)?
双因素身份验证 (2FA) 类似于 MFA 的子集,但不同之处在于 MFA 可能需要两个或多个因素来证明身份。
什么是TOTP(基于时间的一次性密码算法)?
使用 ASP.NET Core Identity 时,默认支持使用 TOTP 的 MFA。此方法可与任何合规的身份验证器应用一起使用,包括:
Microsoft 身份验证器
谷歌身份验证器
什么是 MFA 短信?
与密码身份验证(单因素)相比,带有 SMS 的 MFA 大大提高了安全性。但是,不再建议使用 SMS 作为第二个因素。对于此类实现,存在太多已知的攻击媒介。
什么是在线快速身份识别 (FIDO)?
FIDO 是无密码身份验证的开放标准,允许用户在没有密码的情况下登录。FIDO2 密钥(通常是 USB,但也包括蓝牙或 NFC)通过消除密码风险来增强安全性。
它们目前被认为是最安全的 MFA 方法。
现在,让我们开始配置 2FA。
我们将利用 2FA 与 MVC 项目的集成。首次创建新的 MVC 项目时,可以选择从一开始就生成标识系统,包括“注册”、“登录”和“2FA”。我们的第一步是创建一个新的 MVC 项目。
在 Visual Studio 2022 中,可以完成以下操作:
选择个人帐户标识选项。
或者,您可以使用命令行。
dotnet new mvc -n "2FA" -au individual
创建的项目应如下所示。
现在,运行创建的项目。应显示一个带有登录和注册按钮的欢迎页面。
单击“注册”以创建新用户。
单击“单击此处确认您的帐户”以确认您的电子邮件。
接下来,注销,然后再次登录。点击右上角的电子邮件。
导航到“双因素身份验证”部分。
单击“添加身份验证器应用程序” 应显示双因素身份验证设置屏幕。
如您所见,它是开箱即用的,但没有扫描二维码的选项;它仅适用于代码。
现在,让我们添加二维码功能,允许用户只需扫描二维码即可自动添加密钥。
我们需要访问为我们创建的生成的 cshtml 页面。默认情况下,这些页面位于目录中。但是,如果尚未展开目录,则 dotnet 不会显示文件,除非生成了文件。Areas/Identity/Pages
为此,请运行该命令。
dotnet tool install -g dotnet-aspnet-codegenerator
接下来,我们需要安装所有必需的 NuGet 包。
dotnet add pacakge Microsoft.EntityFrameworkCore.Design
dotnet add package Microsoft.VisualStudio.Web.CodeGeneration.Design
然后,运行代码生成器并指定要检索的页面。默认情况下,如果将其留空,它将生成许多页面。但是,为了避免不必要的页面使您的项目混乱,我们将指定我们需要的特定页面。
cd "your project directory"
dotnet aspnet-codegenerator identity -dc _2FA.Data.ApplicationDbContext --files "Account.Manage.EnableAuthenticator"
若要查看可生成的所有文件,请运行该命令。
dotnet aspnet-codegenerator identity -dc _2FA.Data.ApplicationDbContext -lf
以下是可以生成的所有文件的完整列表。
File List:
Account.\_StatusMessage
Account.AccessDenied
Account.ConfirmEmail
Account.ConfirmEmailChange
Account.ExternalLogin
Account.ForgotPassword
Account.ForgotPasswordConfirmation
Account.Lockout
Account.Login
Account.LoginWith2fa
Account.LoginWithRecoveryCode
Account.Logout
Account.Manage.\_Layout
Account.Manage.\_ManageNav
Account.Manage.\_StatusMessage
Account.Manage.ChangePassword
Account.Manage.DeletePersonalData
Account.Manage.Disable2fa
Account.Manage.DownloadPersonalData
Account.Manage.Email
Account.Manage.EnableAuthenticator
Account.Manage.ExternalLogins
Account.Manage.GenerateRecoveryCodes
Account.Manage.Index
Account.Manage.PersonalData
Account.Manage.ResetAuthenticator
Account.Manage.SetPassword
Account.Manage.ShowRecoveryCodes
Account.Manage.TwoFactorAuthentication
Account.Register
Account.RegisterConfirmation
Account.ResendEmailConfirmation
Account.ResetPassword
Account.ResetPasswordConfirmation
返回到 Visual Studio,现在应该会看到已添加的文件。EnableAuthenticator.cshtml
在编辑文件之前,我们需要下载qrcode.js JavaScript库,它将为我们渲染并生成QR码。将其保存在文件夹中。EnableAuthenticator.cshtmlwwwroot\lib
在这里,我将其重命名为qrcodejs
接下来,创建一个新文件,使用以下代码在 中调用它。qr.jswwwroot\js
window.addEventListener("load", () => {
const uri = document.getElementById("qrCodeData").getAttribute('data-url');
new QRCode(document.getElementById("qrCode"),
{
text: uri,
width: 150,
height: 150
});
});
最后,打开文件,然后:EnableAuthenticator.cshtml
更新该部分以添加对以前下载的库的引用。Scriptsqrcode.js
添加带有调用的文件以生成二维码。qr.js
@section Scripts {
@await Html.PartialAsync("_ValidationScriptsPartial")
<script type="text/javascript" src="~/lib/qrcodejs/qrcode.js"></script>
<script type="text/javascript" src="~/js/qr.js"></script>
}
再次运行应用程序,QR 码现在应该出现。
使用Authenticator应用程序扫描它,它应该可以完美运行。
通过将其添加到身份验证器应用,可以从应用中生成的代码中验证代码。它应该显示 2FA 确认。
现在,尝试注销,然后重新登录。将出现 2FA 表单,提示您输入 2FA 代码。
恭喜,您的 2FA 设置完美。
源代码获取:公众号回复消息【code:19129
】