迁移到 OpenIddict 4.0
新特性
4.0 版本最重要的变更可以在这里找到。
NOTE
除非您使用 MongoDB,否则迁移到 OpenIddict 4.0 不需要对数据库进行更改。
更新包引用
为此,请更新您的 .csproj 文件以引用 OpenIddict 4.x 包。例如:
<ItemGroup>
<!-- OpenIddict 3.x: -->
<PackageReference Include="OpenIddict.AspNetCore" Version="3.1.1" />
<PackageReference Include="OpenIddict.EntityFrameworkCore" Version="3.1.1" />
<!-- OpenIddict 4.x: -->
<PackageReference Include="OpenIddict.AspNetCore" Version="4.10.1" />
<PackageReference Include="OpenIddict.EntityFrameworkCore" Version="4.10.1" />
</ItemGroup>NOTE
迁移到 ASP.NET Core 7.0 不是必需的,因为 OpenIddict 4.0 仍然原生兼容 ASP.NET Core 2.1(仅限 .NET Framework)、 ASP.NET Core 3.1 和 ASP.NET Core 6.0。迁移到更新的 .NET 运行时或 ASP.NET Core 可以单独进行,以实现更简单/解耦的升级:
| Web 框架版本 | .NET 运行时版本 |
|---|---|
| ASP.NET Core 2.1 | .NET Framework 4.6.1 |
| ASP.NET Core 2.1 | .NET Framework 4.7.2 |
| ASP.NET Core 2.1 | .NET Framework 4.8 |
| ASP.NET Core 3.1 | .NET Core 3.1 |
| ASP.NET Core 6.0 | .NET 6.0 |
| ASP.NET Core 7.0 | .NET 7.0 |
| Microsoft.Owin 4.2 | .NET Framework 4.6.1 |
| Microsoft.Owin 4.2 | .NET Framework 4.7.2 |
| Microsoft.Owin 4.2 | .NET Framework 4.8 |
更新端点 URI
OpenIddict 4.0 引入了一个影响端点 URI 计算和解析的行为变更。有关此变更的更多信息, 请阅读 OpenIddict 4.0 中影响 URI 处理的重大变更。
在大多数情况下,调整代码应该仅限于删除端点路径中的前导斜杠以适应新的逻辑:
services.AddOpenIddict()
.AddServer(options =>
{
// OpenIddict 3.x:
options.SetAuthorizationEndpointUris("/connect/authorize")
.SetDeviceEndpointUris("/connect/device")
.SetIntrospectionEndpointUris("/connect/introspect")
.SetLogoutEndpointUris("/connect/logout")
.SetTokenEndpointUris("/connect/token")
.SetUserinfoEndpointUris("/connect/userinfo")
.SetVerificationEndpointUris("/connect/verify");
// OpenIddict 4.x:
options.SetAuthorizationEndpointUris("connect/authorize")
.SetDeviceEndpointUris("connect/device")
.SetIntrospectionEndpointUris("connect/introspect")
.SetLogoutEndpointUris("connect/logout")
.SetTokenEndpointUris("connect/token")
.SetUserinfoEndpointUris("connect/userinfo")
.SetVerificationEndpointUris("connect/verify");
});移除指定目标列表的 AddClaim(s) 调用
如 OpenIddict 4.0 preview1 发布 中所述, 接受 destinations 参数的 AddClaim(s) 扩展已在 4.0 中移除。
相反,开发人员被鼓励使用新的 ClaimsIdentity 和 ClaimsPrincipal 的一次性 SetDestinations() 扩展 (必须在所有声明添加到身份/主体之后调用):
var identity = new ClaimsIdentity(
authenticationType: TokenValidationParameters.DefaultAuthenticationType,
nameType: Claims.Name,
roleType: Claims.Role);
identity.SetClaim(Claims.Subject, await _userManager.GetUserIdAsync(user))
.SetClaim(Claims.Email, await _userManager.GetEmailAsync(user))
.SetClaim(Claims.Name, await _userManager.GetUserNameAsync(user))
.SetClaims(Claims.Role, (await _userManager.GetRolesAsync(user)).ToImmutableArray());
identity.SetScopes(result.Principal.GetScopes());
identity.SetResources(await _scopeManager.ListResourcesAsync(identity.GetScopes()).ToListAsync());
identity.SetDestinations(static claim => claim.Type switch
{
// 当授予 "profile" 作用域时(通过调用 principal.SetScopes(...)),
// 允许 "name" 声明同时存储在访问令牌和身份令牌中
Claims.Name when claim.Subject.HasScope(Scopes.Profile)
=> [Destinations.AccessToken, Destinations.IdentityToken],
// 否则,只将声明存储在访问令牌中
_ => [Destinations.AccessToken]
});如果适用,更新您的 OpenIddict MongoDB 授权
为了匹配其他属性使用的大小写,OpenIddictMongoDbAuthorization.CreationDate 属性在 BSON 表示中使用的名称 已修复为使用驼峰命名法(即 creation_name 而不是 CreationDate)。为了确保现有授权正确更新以使用新名称, 可以使用以下脚本一次性高效地更新所有现有授权:
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using MongoDB.Bson;
using MongoDB.Driver;
using OpenIddict.MongoDb;
var services = new ServiceCollection();
services.AddOpenIddict()
.AddCore()
.UseMongoDb()
.UseDatabase(new MongoClient("mongodb://localhost:27017").GetDatabase("openiddict"));
await using var provider = services.BuildServiceProvider();
var context = provider.GetRequiredService<IOpenIddictMongoDbContext>();
var options = provider.GetRequiredService<IOptionsMonitor<OpenIddictMongoDbOptions>>().CurrentValue;
var database = await context.GetDatabaseAsync(CancellationToken.None);
var authorizations = database.GetCollection<BsonDocument>(options.AuthorizationsCollectionName);
await authorizations.UpdateManyAsync(
filter: Builders<BsonDocument>.Filter.Empty,
update: Builders<BsonDocument>.Update.Rename("CreationDate", "creation_date"));如果适用,将 Portable.BouncyCastle 的引用替换为 BouncyCastle.Cryptography
虽然之前版本的 OpenIddict 使用了由 Claire Novotny 维护的非官方 Portable.BouncyCastle 包(这是当时最好的 .NET Standard 兼容选项), OpenIddict 4.0 已更新为使用 2022 年 11 月发布的官方包 BouncyCastle.Cryptography, 该包具有完整的 .NET Standard 2.0 支持。
如果您的应用程序使用 Portable.BouncyCastle,强烈建议迁移到 BouncyCastle.Cryptography 以避免类型冲突。
如果适用,更新您的自定义存储以使用更新后的签名
OpenIddict 4.x 修复了 IOpenIddictApplicationStore.GetAsync()、IOpenIddictAuthorizationStore.GetAsync()、 IOpenIddictScopeStore.GetAsync() 和 IOpenIddictTokenStore.GetAsync() 的可空性注解,以返回 ValueTask<TResult?> 而不是 ValueTask<TResult>。
实现这些接口并启用了可空引用的开发人员被邀请更新 GetAsync() 方法的签名:
// OpenIddict 3.x:
ValueTask<TResult> GetAsync<TState, TResult>(
Func<IQueryable<TApplication>, TState, IQueryable<TResult>> query,
TState state, CancellationToken cancellationToken);
// OpenIddict 4.x:
ValueTask<TResult?> GetAsync<TState, TResult>(
Func<IQueryable<TApplication>, TState, IQueryable<TResult>> query,
TState state, CancellationToken cancellationToken);虽然不是必需的,但建议也更新 IOpenIddictApplicationStore 的实现,以使用更新后的参数名称 用于 FindByPostLogoutRedirectUriAsync()、FindByRedirectUriAsync()、SetPostLogoutRedirectUrisAsync() 和 SetRedirectUrisAsync():
// OpenIddict 3.x:
IAsyncEnumerable<TApplication> FindByPostLogoutRedirectUriAsync(string address, CancellationToken cancellationToken);
IAsyncEnumerable<TApplication> FindByRedirectUriAsync(string address, CancellationToken cancellationToken);
ValueTask SetPostLogoutRedirectUrisAsync(TApplication application, ImmutableArray<string> addresses, CancellationToken cancellationToken);
ValueTask SetRedirectUrisAsync(TApplication application, ImmutableArray<string> addresses, CancellationToken cancellationToken);
// OpenIddict 4.x:
IAsyncEnumerable<TApplication> FindByPostLogoutRedirectUriAsync(string uri, CancellationToken cancellationToken);
IAsyncEnumerable<TApplication> FindByRedirectUriAsync(string uri, CancellationToken cancellationToken);
ValueTask SetPostLogoutRedirectUrisAsync(TApplication application, ImmutableArray<string> uris, CancellationToken cancellationToken);
ValueTask SetRedirectUrisAsync(TApplication application, ImmutableArray<string> uris, CancellationToken cancellationToken);考虑迁移到新的 OpenIddict 客户端(可选)
OpenIddict 4.0 引入了一个新的客户端堆栈,它原生兼容所有支持的 ASP.NET Core 版本(2.1 在 .NET Framework 上,3.1、6.0 和 7.0)和 Microsoft.Owin 4.2(这意味着它也可以在 ASP.NET 4.6.1 及更高版本上使用)。
有关更多信息,请阅读 OpenIddict 4.0 正式发布。
