关于.NET 8 中Identity的新增功能

以下内容手工翻译来自于 英文阅读无障碍的建议阅读原版。

2023 年 4 月,我写了一篇关于 ASP.NET Core 团队致力于改进 .NET 8 中的身份验证、授权和身份管理的文章。我们提出的计划包括三个关键的可交付成果:

所有三个可交付结果都将随 .NET 8 一起提供。此外,我们还能够为 Blazor Web 应用添加新的标识 UI,该 UI 适用于两种新的呈现模式(服务器和 WebAssembly)。

让我们看一下 .NET 8 中的新更改启用的几个方案。在这篇博文中,我们将介绍:

让我们看一下使用新Identity功能的最简单方案。

基本 Web API 后端

一个简单的方法是在基本的Web API应用程序中启用新的授权。同样的应用程序也可以用作Blazor WebAssembly、Angular、React和其他单页Web应用程序(SPA)的后端。假设您从包含OpenAPI的.NET 8中的ASP.NET Core Web API项目开始,您可以通过几个步骤添加身份验证。

Identity是“选择加入”的,因此需要添加一些包:

您可以使用NuGet软件包管理器或命令行添加这些软件包。例如,要使用命令行添加软件包,请转到项目文件夹并运行以下dotnet命令:

dotnet add package Microsoft.AspNetCore.Identity.EntityFrameworkCore
dotnet add package Microsoft.EntityFrameworkCore.InMemory

Identity允许您自定义用户信息和用户数据库,以满足.NET Core框架未提供的要求。对于我们的基本示例,我们将使用默认的用户信息和数据库。为此,我们将添加一个继承自IdentityUser的新类到项目中:MyUser IdentityUser

class MyUser : IdentityUser {}

添加一个继承自IdentityDbContext的新类

class AppDbContext(DbContextOptions options) : 
        IdentityDbContext(options)
{
}

通过提供这个特殊的构造函数可以为不同环境配置数据库。

要为应用设置身份验证,请打开Program.cs文件。使用以下代码配置身份验证使用Cookie方式进行身份验证,并启用授权检查:

builder.Services.AddAuthentication(IdentityConstants.ApplicationScheme)
    .AddIdentityCookies();
builder.Services.AddAuthorizationBuilder();

配置EF Core数据库。这里我们将使用内存数据库并命名为”AppDb”。用于演示目的,这样每次重新启动应用程序都可以测试注册和登录流程(每次运行都将使用新的数据库)。使用SQLite可以在会话之间保存用户,但需要通过migrations正确创建数据库,如EF Core入门教程中所示。您可以为生产代码使用SQL Server等关系数据库提供程序。。

builder.Services.AddDbContext(
    options => options.UseInMemoryDatabase("AppDb"));

配置身份验证使用EF Core数据库,并公开身份验证端点:

builder.Services.AddIdentityCore()
    .AddEntityFrameworkStores()
    .AddApiEndpoints();

映射身份验证端点的路由。此代码应放在builder.Build()调用之后:

app.MapIdentityApi();

现在应用已经为身份验证和授权做好准备!要保护一个端点,请在定义授权路由的地方使用扩展方法。如果使用基于控制器的解决方案,可以将属性添加到控制器或操作中 [Authorize]

要测试应用,运行它并导航到Swagger UI。展开受保护的端点,选择“尝试它”,然后选择“执行”。端点报告为404 – 没有找到,这比报告401 – 没有授权更加安全,因为它不会暴露端点的存在。

现在展开注册表单并填写您的凭据。如果输入无效的电子邮件地址或错误的密码,结果将包含验证错误/register

在这个示例中,错误使用ProblemDetails格式返回,所以客户端可以很容易解析它们并根据需要显示验证错误。我将在单独的Blazor WebAssembly应用中展示一个示例。

成功注册后会返回200响应。您现在可以展开登录表单并输入相同的凭据。注意,有一些额外的参数不需要此示例并可以删除。确保将useCookies设置为true。成功登录后会返回一个带有响应头部cookie的200响应。

现在您可以重新运行受保护的端点,它应返回有效结果。因为基于cookie的身份验证已经安全地内置到浏览器中“就可以工作”。您刚刚使用身份验证保护了第一个端点!

一些Web客户端默认可能不会在请求头中包含cookie。如果使用API测试工具,您可能需要在设置中启用cookie。JavaScript API默认不包含cookie。您可以通过将设置为HttpClient请求的选项来启用它们。同样,在Blazor WebAssembly应用中运行的需要包含凭据,如:fetchcredentialsincludeHttpClientHttpRequestMessage

request.SetBrowserRequestCredential(BrowserRequestCredentials.Include);

接下来,让我们跳转到 Blazor Web 应用。

Blazor 标识 UI

我们团队实现身份验证UI,其中包括注册、登录和多重身份验证配置选项的功能,在Blazor中是一个我们能够实现的远大目标。身份验证选择“个人账户”选项时,模板会自动生成UI的源代码。与早期版本需要自行定制的身份验证UI不同,现在的模板会生成所有源代码以便需要修改时自由调整。新版本使用Razor组件构建,同时支持服务器端和WebAssembly Blazor应用。

图片[1]-关于.NET 8 中Identity的新增功能-天星网创

新型Blazor Web模型可以配置是否在服务器端或WebAssembly客户端渲染UI。选择WebAssembly模式时,服务器仍会处理所有身份验证和授权请求,并生成跟踪身份验证状态的自定义实现代码。

状态提供程序使用PersistentComponentState类预渲染身份验证状态并持久化到页面。客户端WebAssembly应用中的组件使用该组件在服务器和浏览器之间同步身份验证状态。状态提供程序在自动交互或服务器交互模式下运行也可能命名为 AuthenticationStateProviderPersistentAuthenticationStateProviderPersistingRevalidatingAuthenticationStateProviderIdentityRevalidatingAuthenticationStateProvider

尽管本文博客示例只关注简单的用户名密码登录场景,但ASP.NET Identity还支持电子邮件交互如账户确认和密码恢复功能。也可以配置多重身份验证。UI包含所有这些功能的组件。

添加外部登录名

添加外部登录 经常被问到的一个问题是如何将社交网站的外部登录与ASP.NET Core Identity集成。从Blazor web应用默认项目开始,添加外部登录只需要几步:

首先,需要在社交网站开发者门户注册应用。例如,要添加Twitter登录,去Twitter开发者门户创建一个新应用。需要提供一些基本信息来获取客户端凭据。创建应用后,导航到应用设置并点击“编辑”身份验证。为应用类型指定“原生应用”,以正确运行流程,并打开“从用户请求电子邮件”。需要提供回调URL。在这个例子中,我们使用默认的Blazor web应用模板回调URL。可以将其改为匹配应用的URL(即用自己的端口替换)。同时注意API密钥和密钥。:5001/signin-twitter5001

然后,向应用添加相应的身份验证包。有一个社区维护的列表,包含许多选择的ASP.NET Core OAuth 2.0社交身份验证提供程序。可以根据需要混合多个外部登录。对于Twitter,我添加了AspNet.Security.OAuth.Twitter包。

在服务器项目的根目录下的命令提示符中运行以下命令存储API密钥(客户端ID)和密钥:

dotnet user-secrets set "Twitter:ApiKey" ""
dotnet user-secrets set "TWitter:ApiSecret" ""

最后,通过替换Program.cs中的代码进行登录配置:

builder.Services.AddAuthentication(IdentityConstants.ApplicationScheme)
    .AddIdentityCookies();

使用以下代码:

builder.Services.AddAuthentication(IdentityConstants.ApplicationScheme)
    .AddTwitter(opt =>
        {
            opt.ClientId = builder.Configuration["Twitter:ApiKey"]!;
            opt.ClientSecret = builder.Configuration["Twitter:ApiSecret"]!;
        })
    .AddIdentityCookies();

对于实现ASP.NET Core Identity,Cookie是首选且最安全的方法。如果需要,也支持令牌,需要配置IdentityConstants.BearerScheme。令牌是专有的,基于令牌的流程仅用于简单场景,不实现OAuth 2.0或OIDC标准

下一步呢?相信不出所料,你已经完成了。运行应用时,登录页面会自动检测外部登录并提供使用它的按钮。

图片[2]-关于.NET 8 中Identity的新增功能-天星网创

当您登录并授权应用程序时,您将被重定向回并进行身份验证。

保护 Blazor WebAssembly 应用

添加新的身份API的主要动机是使开发人员更容易保护基于浏览器的应用,包括单页应用(SPA)和Blazor WebAssembly。不论你使用内置的身份提供者、自定义登录还是像Microsoft Entra这样的云服务,最终结果都是带有声明和角色的已认证身份,或者未认证身份。在Blazor中,你可以通过向组件或承载组件的页面添加属性来保护Razor组件。你也可以通过向路由定义添加扩展方法来保护路由。

这个例子的完整源代码可在Blazor示例仓库中找到

标签提供了一种简单的方式来处理用户有权访问的内容。身份状态可以通过属性访问。考虑以下情况:AuthorizeViewcontext

Welcome to my page!

We're checking your credentials...
You are authenticated @context.User.Identity?.Name
You are not authenticated!

欢迎语将显示给每个人。在Blazor WebAssembly的情况下,当客户端可能需要通过API调用异步进行身份验证时,内容将在查询和解析身份状态时显示。然后,根据您是否已通过身份验证,您将看到您的名字或一条消息表示您未通过身份验证。客户端如何知道您是否已通过身份验证?这就是AuthenticationStateProvider发挥作用的地方。

页面被包裹在一个提供者中。这个提供者负责跟踪身份验证状态,并使其可供应用的其他部分使用。注入到提供者中,用于跟踪状态。也注入到组件中。当身份验证状态发生变化时,提供者会通知组件,内容相应地进行更新。App.razorCascadingAuthenticationStateAuthenticationStateProviderAuthenticationStateProviderAuthorizeViewAuthorizeView

首先,我们要确保API调用正确持久化凭据。为此,我创建了一个名为的处理程序。 .CookieHandler

public class CookieHandler : DelegatingHandler
{
    protected override Task SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        request.SetBrowserRequestCredentials(BrowserRequestCredentials.Include);
        return base.SendAsync(request, cancellationToken);
    }
}

在中添加了处理程序,并使用客户端工厂配置了一个专用于身份验证的特殊客户端。

builder.Services.AddTransient();
builder.Services.AddHttpClient(
    "Auth",
    opt => opt.BaseAddress = new Uri(builder.Configuration["AuthUrl"]!))
    .AddHttpMessageHandler();

注意:身份验证组件是可选的,通过包提供。客户端工厂和扩展方法来自Microsoft.Extensions.Http包。

是暴露身份API的ASP.NET Core服务器的URL。然后,我创建了一个从继承的提供者,并重写了方法。主要逻辑如下:AuthUrlCookieAuthenticationStateProviderAuthenticationStateProviderGetAuthenticationStateAsync

var unauthenticated = new ClaimsPrincipal(new ClaimsIdentity());
var userResponse = await _httpClient.GetAsync("manage/info");
if (userResponse.IsSuccessStatusCode) 
{
    var userJson = await userResponse.Content.ReadAsStringAsync();
    var userInfo = JsonSerializer.Deserialize(userJson, jsonSerializerOptions);
    if (userInfo != null)
    {
        var claims = new List
        {
            new(ClaimTypes.Name, userInfo.Email),
            new(ClaimTypes.Email, userInfo.Email)
        };
        var id = new ClaimsIdentity(claims, nameof(CookieAuthenticationStateProvider));
        user = new ClaimsPrincipal(id);
    }
}
return new AuthenticationState(user);

用户信息终结点是安全的,因此,如果用户未经过身份验证,请求将失败,并且该方法将返回未经身份验证的状态。否则,它将生成相应的标识和声明,并返回经过身份验证的状态。

应用如何知道状态何时发生更改?下面是使用标识 API 从 Blazor WebAssembly 登录的外观:

async Task LoginAndGetAuthenticationState()
{
    var result = await _httpClient.PostAsJsonAsync(
        "login?useCookies=true", new
        {
            email,
            password
        });
        return await GetAuthenticationStateAsync();
}
NotifyAuthenticationStateChanged(LoginAndGetAuthenticationState());

如果登录成功,会调用基类上的方法来通知提供者状态已更改。它传入请求新的身份验证状态的结果,以验证Cookie是否存在。提供者然后会更新组件,用户将看到已认证的内容。NotifyAuthenticationStateChangedAuthenticationStateProviderAuthorizeView

令 牌

在极少数不支持Cookie的客户端情况下,登录API提供了一个参数来请求令牌。会发出一个专有的令牌(专属于ASP.NET Core身份平台),这个令牌可以用于认证后续请求。令牌会以承载者令牌的形式通过头部传递。也提供了一个刷新令牌。这允许应用程序在旧令牌过期时请求一个新的令牌,而无需强制用户再次登录。这些令牌不是标准的JSON Web令牌(JWT)。在此做出这样决定是有意为之,因为内置身份主要用于简单场景。令牌选项不是一个全功能的身份服务提供商或令牌服务器,而是为无法使用Cookie的客户端提供一个Cookie选项的替代方案。

不确定是否需要令牌服务器吗?阅读一份文档可以帮助您选择正确的ASP.NET Core身份解决方案。寻找更高级的身份解决方案?请查看我们为ASP.NET Core准备的身份管理解决方案列表。

文档和示例

第三项交付物是文档和示例。我们已经引入了新的文档,并将在.NET 8发布前添加新的文章和示例。请关注问题#29452——.NET 8种身份的文档和示例,以跟踪进度。请使用该问题来沟通您需要的额外文档或示例。您还可以链接到各种文档的具体问题,并在那里提供反馈。

结论

.NET 8中的新身份功能使得保护应用程序比以往任何时候都更简单。如果您的需求很简单,现在只需要几行代码就可以为应用程序添加身份验证和授权功能。新的API使得使用基于Cookie的身份验证和授权来保护Web API端点成为可能。对于无法使用Cookie的客户端,也提供了基于令牌的选项。

#.Net 2023开发者大会#

#.Net Conf 2023#

#微软发布.NET8开源开发平台#

#头条创作挑战赛#

#从今天起记录我的2023#

#妙笔生花创作挑战#

#记录我的2023#

限时特惠:本站每日持续更新海量各大内部创业教程,永久会员享受全站资源免费下载.www.heook.com
站长微信:wc764800

© 版权声明
THE END
喜欢就支持一下吧
点赞6 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容