• 聊聊.NET Core中的Identity API endpoints
  • 发布于 1周前
  • 56 热度
    0 评论
一. 什么是Asp.Net Core Identity以及为什么需要它?

ASP.NET Core Identity 是一个附加层,随 ASP.NET Core 一起发布,在 ASP.NET Core 应用程序中管理用户账户提供了多种服务。这包括每个服务的抽象和默认实现。ASP.NET Core Identity 允许你在应用程序中存储用户账户、管理用户详细信息、启用双因素认证以及将第三方登录关联到用户账户。其核心功能是将用户账户存储在你的应用中,并使用这些账户进行登录。


在核心 Identity 系统中,有三个主要的抽象需要考虑:
DataModel—ASP.NET Core Identity 模型的基本类型。包括 IdentityUser 和 IdentityRole 等类型。
Stores—用于存储和检索数据模型类型实例的持久层。包括 IUserStore<> 和 IRoleStore<> 等接口,以及一系列细粒度的接如 IUserPasswordStore<>、IUserAuthenticatorKeyStore<> 等。

Managers—在存储之上提供服务层以管理用户,有点类似于仓储层。有三个主要的抽象:
UserManager—对用户执行相对高级的操作,例如通过用户名和电子邮件创建用户,处理密码哈希、生成规范化名称、更新安全戳等。
RoleManager—类似于 UserManager,执行与角色相关的高级操作,例如添加或移除角色的声明。
SignInManager—提供用于用户登录和注销、验证双因素代码、检查账户锁定等的高级 API。

Managers提供了相对高级的 API 用于与 Identity 进行交互,但你仍然需要实际调用Managers接口才能使用它们。例如,为了帮你完成这个阶段,微软长期提供了一个默认的 UI 包,Microsoft.AspNetCore.Identity.UI,其中包含了超过 30 个用于处理 Identity 的 Razor Pages。这些页面包括登录和注销页面、更改电子邮件和密码的页面、启用和管理双因素认证(2FA)代码的页面等。

默认 UI 添加的大量代码为你节省了编写代码的时间。你可以使用脚手架工具(如上所示)将这些代码导入到你的应用中,当然你也可以将UI层扔掉,在自己的MVC里面重新实现这些功能,也可以将他们封装成web api,这无疑加大了工作量。不幸的是,这让你处于一个尴尬的境地。如果你想使用 ASP.NET Core Identity在应用内存储用户账户,你不得不选择以下三条主要路径之一:
1.使用默认的 Razor Pages UI样式。这意味着你只能使用默认的样式,除了可以在全局级别进行主题设置之外。这对于真正的商业项目不太理想。
2.使用默认的 Razor Pages UI,然后自定义 Razor 模板。你可以自定义自己的样式,但需要更新很多页面,并且保持脚手架代码的最新状态非常困难。
3.自己构建整个 UI,这带来了大量的工作,因为登录和账户页面可能是你的应用中最敏感的部分。

上面存在这么多问题,那我们需要解决这些问题,那么Identity API endpoints可以解决上面问题!

二. 什么是Identity API endpoints
在.NET 8中,Identity可以将最小化api终结点添加到你的应用程序中,这些终结点就相当于Razor Pages UI调用的接口,主要解决了以下两个问题:
可以非常容易创建自己的UI,这使得应用的身份/账户 UI 样式与应用的其他部分保持一致。
你可以为 SPA 应用或移动应用颁发访问令牌,以便在调用 ASP.NET Core 应用中的其他 API 时使用。
然而Cookies在手机端是很难管理的,使用token是一个很好的选择。

三. 添加Identity api到Asp.Net Core应用程序
我们创建一个应用程序并将Identity api添加到应用程序中,使用dotnet new 命令创建出来的api是不包含Identity api
添加关联的包
针对这个例子我们使用EF Core SQLite数据库,添加如下包
dotnet add package Microsoft.EntityFrameworkCore.SQLite
dotnet add package Microsoft.EntityFrameworkCore.Design 
dotnet add package Microsoft.AspNetCore.Identity.EntityFrameworkCore
配置EF Core
为了使用EF Core我们需要提前做一些关联的配置,首先我们需要在我们应用程序中实现一个DbContext下面代码在应用程序中实现了一个DbContext
public class AppDbContext : DbContext
{
    public AppDbContext(DbContextOptions<AppDbContext> options)
     : base(options)
    {
    }
}
调用WebApplicationBuilder的AddDbContext<>来注册AppDbContext
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
// 堆代码 duidaima.com
// Add EF Core
builder.Services.AddDbContext<AppDbContext>(options =>
    options.UseSqlite(builder.Configuration.GetConnectionString("DefaultConnection")));
如上所示,我们配置 EF Core 以使用我们的 AppDbContext 类、使用 SQLite,并使用名为"DefaultConnection"的连接字符串。我们可以在 appsettings.json 中定义连接字符串
{
  "ConnectionStrings": {
    "DefaultConnection": "Data Source=my_test_app.db"
  }
}
上面是EF Core的配置方式,我们以相同的方式配置Identity,我们接下来配置Identity api,我们需要做两件事:
1.创建一个从 IdentityUser 派生的类型
2.更新我们的 AppDbContext 继承自 IdentityDbContext<>
第一点没有严格限制,除非你要扩展用户表,你可以直接在应用中使用 IdentityUser。但由于有些时候想要自定义用户类型,我们实现自己一个用户类
public class AppUser : IdentityUser
{
    // Add customisations here later
}
public class AppDbContext : IdentityDbContext<AppUser>
{
    public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
    {
    }
}
你可以使用新的 AddIdentityApiEndpoints<> 方法添加 Identity 服务,并配置标准的 Identity EF Core 存储:
builder.Services    
.AddIdentityApiEndpoints<AppUser>()    
.AddEntityFrameworkStores<AppDbContext>();
AddApiEndpoints方法做了以下几件事:
1.配置 Bearer 和 Cookie 认证
2.添加核心 Identity 服务,如 UserManager

3.添加 Identity API 端点所需的服务,如 SignInManager、令牌提供程序和一个无操作的 IEmailSender 实现


创建数据库
应用程序为了EF Core,我们需要创建一个migration并且更新数据库,如果你应用编译成功你能够通过下面两个步骤:
dotnet ef migrations add InitialSchema
dotnet ef database update
上述操作如果比较顺利,我们应该创建 my_test_app.db SQLite 数据库文件。
授权API
最终,我们希望能够通过授权来保护我们的 API,因此为了确保这一点正常工作,让我们在天气预报端点添加一个授权要求:
 [HttpGet(Name = "GetWeatherForecast")]
 [Authorize]
 public IEnumerable<WeatherForecast> Get()
 {
     return Enumerable.Range(1, 5).Select(index => new WeatherForecast
     {
         Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
         TemperatureC = Random.Shared.Next(-20, 55),
         Summary = Summaries[Random.Shared.Next(Summaries.Length)]
     })
     .ToArray();
 }
Identity api终结点地址
在 WebApplication 上调用 MapIdentityApi<> 将 Identity 端点添加到你的应用程序中。这将为你的应用程序添加各种端点。有时候我们需要修改终结点路径,比如 /account 或 /identity,这样一来,端点 /login 和 /confirmEmail 就会变成 /account/login 和 /account/confirmEmail。你可以使用 MapGroup 添加前缀,如以下示例所示:
app.MapGroup("/account").MapIdentityApi<AppUser>();
查看Identity api
上面所有配置完成之后,运行应用程序查看所有apis:

我们可以看到/weatherforecast,使用MapIdentityApi<>()方法添加了下面所有终结点,你可以使用 SwaggerUI 与 API 交互,但是在.NET 9中微软已经将Swagger移除,由于该开源项目长期没有更新,所以推荐使用 vs内置的.http处理器。
测试
我们请求WeatherForecast接口获取到401状态码,说明没有权限

注册用户
我们首先要查看的是 /register 端点(在我的示例中公开为 /account/register)。这是一个 POST 端点,我们需要向其发送电子邮件、用户名和密码:

注意这里password必须满足IdentityOptions 标准的需求,包含长度和复杂度。

查看Token 
假设用户已正确创建,我们现在需要检索一个访问令牌。我们可以使用 /login 路径来实现这一点,如果你的用户名和密码正确,这将返回一个类似于你之前看到的响应:

调用受保护api
我们现在有access_token,我们能够使用它调用受保护的API:

用户评论