项目

OpenIddict 模块(专业版)

您必须拥有 ABP 团队版或更高许可证 才能使用此模块。

该模块为 OpenIddict 库提供了集成和管理功能;

  • 基于 OpenIddict-core 库构建。
  • 管理系统中的应用程序API 范围
  • 为客户端设置权限

有关模块功能的概述,请参见模块描述页面

如何安装

从 6.0.0-rc1 版本开始,OpenIddict 已在 启动模板 中预安装。因此,无需手动安装。您也可以按照 逐步迁移到 OpenIddict 指南 迁移现有应用程序。

此模块遵循 模块开发最佳实践指南,由多个 NuGet 和 NPM 包组成。如果您想了解这些包及其之间的关系,请参阅该指南。

您可以访问Identity 模块包列表页面查看与此模块相关的包列表。

用户界面

菜单项

OpenIddict 模块在“管理”菜单项下的“主”菜单中添加了以下项目:

  • 应用程序:应用程序管理页面。
  • 范围:范围管理页面。

OpenIddictProMenus 类包含了菜单项名称的常量。

页面

应用程序管理

应用程序页面用于管理 OpenIddict 应用程序。一个 application 代表可以从您的认证服务器请求令牌的托管应用程序。

openiddict-applications-page

您可以在此页面创建新应用程序或编辑现有应用程序:

openiddict-edit-application-modal

API 范围管理

OpenIddict 模块允许管理 API 范围。要允许应用程序为 API 请求访问令牌,您需要定义 API 范围。

openiddict-api-resources-page

您可以在此页面创建新的 API 资源或编辑现有的 API 资源:

openiddict-edit-api-scope-modal

数据种子

当您运行 .DbMigrator 应用程序时,此模块会向数据库添加一些初始数据(参见数据种子系统):

  • 创建标准的身份资源,包括角色、个人资料、电话、openid、电子邮件和地址。
  • 创建应用程序。
  • 创建 API 范围。

您可以在应用程序管理页面中删除或编辑已创建的应用程序。

选项

OpenIddictBuilder

OpenIddictBuilder 可以在您的 OpenIddict 模块PreConfigureServices 方法中配置。

示例:

public override void PreConfigureServices(ServiceConfigurationContext context)
{
    PreConfigure<OpenIddictBuilder>(builder =>
    {
        //在此设置选项...
    });
}

OpenIddictBuilder 包含多种扩展方法来配置 OpenIddict 服务:

  • AddServer() 在 DI 容器中注册 OpenIddict 令牌服务器服务。包含 OpenIddictServerBuilder 配置。
  • AddCore() 在 DI 容器中注册 OpenIddict 核心服务。包含 OpenIddictCoreBuilder 配置。
  • AddValidation() 在 DI 容器中注册 OpenIddict 令牌验证服务。包含 OpenIddictValidationBuilder 配置。

OpenIddictCoreBuilder

OpenIddictCoreBuilder 包含用于配置 OpenIddict 核心服务的扩展方法。

示例:

public override void PreConfigureServices(ServiceConfigurationContext context)
{
    PreConfigure<OpenIddictCoreBuilder>(builder =>
    {
        //在此设置选项...
    });
}

这些服务包括:

  • 添加 ApplicationStoreAuthorizationStoreScopeStoreTokenStore
  • 替换 ApplicationManagerAuthorizationManagerScopeManagerTokenManager
  • 替换 ApplicationStoreResolverAuthorizationStoreResolverScopeStoreResolverTokenStoreResolver
  • 设置 DefaultApplicationEntityDefaultAuthorizationEntityDefaultScopeEntityDefaultTokenEntity

OpenIddictServerBuilder

OpenIddictServerBuilder 包含用于配置 OpenIddict 服务器服务的扩展方法。

示例:

public override void PreConfigureServices(ServiceConfigurationContext context)
{
    PreConfigure<OpenIddictServerBuilder>(builder =>
    {
        //在此设置选项...
    });
}

这些服务包括:

  • 注册声明、范围。
  • 设置 Issuer URI,该 URI 用作从发现端点返回的端点 URI 的基础地址。
  • 添加开发签名密钥、加密/签名密钥、凭据和证书。
  • 添加/删除事件处理器。
  • 启用/禁用授权类型。
  • 设置认证服务器端点 URI。

OpenIddictValidationBuilder

OpenIddictValidationBuilder 包含用于配置 OpenIddict 验证服务的扩展方法。

示例:

public override void PreConfigureServices(ServiceConfigurationContext context)
{
    PreConfigure<OpenIddictValidationBuilder>(builder =>
    {
        //在此设置选项...
    });
}

这些服务包括:

  • AddAudiences() 用于资源服务器。
  • SetIssuer() URI,用于在使用提供者发现时确定 OAuth 2.0/OpenID Connect 配置文档的实际位置。
  • SetConfiguration() 用于配置 OpenIdConnectConfiguration
  • UseIntrospection() 使用内省而不是本地/直接验证。
  • 添加加密密钥、凭据和证书。
  • 添加/删除事件处理器。
  • SetClientId() 用于在与远程授权服务器通信时设置客户端标识符 client_id(例如用于内省)。
  • SetClientSecret() 用于在与远程授权服务器通信时设置标识符 client_secret(例如用于内省)。
  • EnableAuthorizationEntryValidation() 启用授权验证,通过为每个 API 请求进行数据库调用来确保 access token 仍然有效。*注意:*这可能会对性能产生负面影响,并且只能与基于 OpenIddict 的授权服务器一起使用。
  • EnableTokenEntryValidation() 启用授权验证,通过为每个 API 请求进行数据库调用来确保 access token 仍然有效。*注意:*这可能会对性能产生负面影响,并且在 OpenIddict 服务器配置为使用引用令牌时是必需的。
  • UseLocalServer() 注册 OpenIddict 验证/服务器集成服务。
  • UseAspNetCore() 在 DI 容器中为 ASP.NET Core 注册 OpenIddict 验证服务。

内部结构

领域层

聚合

OpenIddictApplication

OpenIddictApplications 表示可以从您的 OpenIddict 服务器请求令牌的应用程序。

  • OpenIddictApplications(聚合根):表示一个 OpenIddict 应用程序。
    • ClientId (字符串):与当前应用程序关联的客户端标识符。
    • ClientSecret (字符串):与当前应用程序关联的客户端密钥。出于安全原因,可能被哈希或加密。
    • ConsentType (字符串):与当前应用程序关联的同意类型。
    • DisplayName (字符串):与当前应用程序关联的显示名称。
    • DisplayNames (字符串):与当前应用程序关联的本地化显示名称,序列化为 JSON 对象。
    • Permissions (字符串):与当前应用程序关联的权限,序列化为 JSON 数组。
    • PostLogoutRedirectUris (字符串):与当前应用程序关联的注销回调 URL,序列化为 JSON 数组。
    • Properties (字符串):与当前应用程序关联的附加属性,序列化为 JSON 对象或 null。
    • RedirectUris (字符串):与当前应用程序关联的回调 URL,序列化为 JSON 数组。
    • Requirements (字符串):与当前应用程序关联的要求。
    • Type (字符串):与当前应用程序关联的应用程序类型。
    • ClientUri (字符串):关于客户端的更多信息的 URI。
    • LogoUri (字符串):客户端徽标的 URI。
OpenIddictAuthorization

OpenIddictAuthorizations 用于保存允许的范围、授权流程类型。

  • OpenIddictAuthorization(聚合根):表示一个 OpenIddict 授权。
    • ApplicationId (Guid?):与当前授权关联的应用程序。
    • Properties (字符串):与当前授权关联的附加属性,序列化为 JSON 对象或 null。
    • Scopes (字符串):与当前授权关联的范围,序列化为 JSON 数组。
    • Status (字符串):当前授权的状态。
    • Subject (字符串):与当前授权关联的主题。
    • Type (字符串):当前授权的类型。
OpenIddictScope

OpenIddictScopes 用于保存资源的范围。

  • OpenIddictScope(聚合根):表示一个 OpenIddict 范围。
    • Description (字符串):与当前范围关联的公共描述。
    • Descriptions (字符串):与当前范围关联的本地化公共描述,序列化为 JSON 对象。
    • DisplayName (字符串):与当前范围关联的显示名称。
    • DisplayNames (字符串):与当前范围关联的本地化显示名称,序列化为 JSON 对象。
    • Name (字符串):与当前范围关联的唯一名称。
    • Properties (字符串):与当前范围关联的附加属性,序列化为 JSON 对象或 null。
    • Resources (字符串):与当前范围关联的资源,序列化为 JSON 数组。
OpenIddictToken

OpenIddictTokens 用于持久化应用程序令牌。

  • OpenIddictToken(聚合根):表示一个 OpenIddict 令牌。
    • ApplicationId (Guid?):与当前令牌关联的应用程序。
    • AuthorizationId (Guid?):与当前令牌关联的授权。
    • CreationDate (DateTime?):当前令牌的 UTC 创建日期。
    • ExpirationDate (DateTime?):当前令牌的 UTC 过期日期。
    • Payload (字符串):当前令牌的有效负载(如果适用)。仅用于引用令牌,出于安全原因可能被加密。
    • Properties (字符串):与当前令牌关联的附加属性,序列化为 JSON 对象或 null。
    • RedemptionDate (DateTime?):当前令牌的 UTC 兑换日期。
    • ReferenceId (字符串):与当前令牌关联的引用标识符(如果适用)。仅用于引用令牌,出于安全原因可能被哈希或加密。
    • Status (字符串):当前令牌的状态。
    • Subject (字符串):与当前令牌关联的主题。
    • Type (字符串):当前令牌的类型。

存储

此模块实现了 OpenIddict 存储:

  • IAbpOpenIdApplicationStore
  • IOpenIddictAuthorizationStore
  • IOpenIddictScopeStore
  • IOpenIddictTokenStore
存储库

此模块中定义了以下自定义存储库:

  • IOpenIddictApplicationRepository
  • IOpenIddictAuthorizationRepository
  • IOpenIddictScopeRepository
  • IOpenIddictTokenRepository
领域服务

此模块不包含任何领域服务,但重写了以下服务:

  • AbpApplicationManager 用于填充/获取包含 ClientUriLogoUriAbpApplicationDescriptor 信息。

设置

此模块未定义任何设置。

应用层

应用服务

  • ApplicationAppService(实现 IApplicationAppService):实现应用程序管理 UI 的用例。
  • ScopeAppService(实现 IScopeAppService):实现 API 范围管理 UI 的用例。

数据库提供程序

通用

表/集合前缀与架构

默认情况下,所有表/集合都使用 OpenIddict 前缀。如果您需要更改表前缀或设置架构名称(如果您的数据库提供程序支持),请在 AbpOpenIddictDbProperties 类上设置静态属性。

连接字符串

此模块使用 AbpOpenIddict 作为连接字符串名称。如果您未定义具有此名称的连接字符串,它将回退到 Default 连接字符串。

有关详细信息,请参阅连接字符串文档。

Entity Framework Core

  • OpenIddictApplications
  • OpenIddictAuthorizations
  • OpenIddictScopes
  • OpenIddictTokens

MongoDB

集合
  • OpenIddictApplications
  • OpenIddictAuthorizations
  • OpenIddictScopes
  • OpenIddictTokens

权限

有关为此模块定义的所有权限,请参阅 AbpOpenIddictProPermissions 类成员。

ASP.NET Core 模块

此模块集成了 ASP.NET Core,为四种协议提供了内置的 MVC 控制器。它使用 OpenIddict 的 直通模式

AuthorizeController -> connect/authorize
TokenController     -> connect/token
LogoutController    -> connect/logout
UserInfoController  -> connect/userinfo

AbpOpenIddictAspNetCoreOptions

AbpOpenIddictAspNetCoreOptions 可以在您的 OpenIddict 模块PreConfigureServices 方法中配置。

示例:

PreConfigure<AbpOpenIddictAspNetCoreOptions>(options =>
{
    //在此设置选项...
});

AbpOpenIddictAspNetCoreOptions 属性:

  • UpdateAbpClaimTypes(default: true):更新 AbpClaimTypes 以兼容 Openiddict 声明。
  • AddDevelopmentEncryptionAndSigningCertificate(default: true):注册(并在必要时生成)用户特定的开发加密/开发签名证书。

自动移除孤立的令牌/授权

自动移除孤立令牌/授权的后台任务。可以通过 TokenCleanupOptions 来配置管理它。

TokenCleanupOptions 可以在您的 OpenIddict 模块PreConfigureServices 方法中配置。

示例:

PreConfigure<TokenCleanupOptions>(options =>
{
    //在此设置选项...
});

TokenCleanupOptions 属性:

  • IsCleanupEnabled (默认:true):启用/禁用令牌清理。
  • CleanupPeriod (默认:3,600,000 毫秒):设置清理周期。
  • DisableAuthorizationPruning:设置一个布尔值,指示是否应禁用授权修剪。
  • DisableTokenPruning:设置一个布尔值,指示是否应禁用令牌修剪。
  • MinimumAuthorizationLifespan (默认:14 天):设置授权必须具有的最短生命周期才能被修剪。不能少于 10 分钟。
  • MinimumTokenLifespan (默认:14 天):设置令牌必须具有的最短生命周期才能被修剪。不能少于 10 分钟。

在 Access_token 和 Id_token 中更新声明

声明主体工厂 可用于向 ClaimsPrincipal 添加/删除声明。

AbpDefaultOpenIddictClaimDestinationsProvider 服务将默认将 NameEmailRole 类型的声明添加到 access_tokenid_token 中,其他声明默认仅添加到 access_token,并移除 IdentitySecurityStampClaimType 秘密声明。

创建一个继承自 IAbpOpenIddictClaimDestinationsProvider 的服务并将其添加到 DI 中,以完全控制声明的目标。

public class MyClaimDestinationsProvider : IAbpOpenIddictClaimDestinationsProvider, ITransientDependency
{
    public virtual Task SetDestinationsAsync(AbpOpenIddictClaimDestinationsProviderContext context)
    {
        // ...
        return Task.CompletedTask;
    }
}

Configure<AbpOpenIddictClaimDestinationsOptions>(options =>
{
    options.ClaimDestinationsProvider.Add<MyClaimDestinationsProvider>();
});

详细资料请参阅:OpenIddict 声明目标

禁用访问令牌加密

ABP 默认为兼容性禁用了 access token encryption,如果需要可以手动启用。

public override void PreConfigureServices(ServiceConfigurationContext context)
{
    PreConfigure<OpenIddictServerBuilder>(builder =>
    {
        builder.Configure(options => options.DisableAccessTokenEncryption = false);
    });
}

禁用传输安全要求

默认情况下,OpenIddict 要求所有端点使用 HTTPS。如果需要,您可以禁用它。您只需配置 OpenIddictServerAspNetCoreOptions 并将 DisableTransportSecurityRequirement 设置为 true

Configure<OpenIddictServerAspNetCoreOptions>(options =>
{
    options.DisableTransportSecurityRequirement = true;
});

https://documentation.openiddict.com/configuration/token-formats.html#disabling-jwt-access-token-encryption

请求/响应过程

OpenIddict.Server.AspNetCore 添加了一个认证方案(Name: OpenIddict.Server.AspNetCore, handler: OpenIddictServerAspNetCoreHandler)并实现了 IAuthenticationRequestHandler 接口。

它将在 AuthenticationMiddleware 中首先执行,并可以短路当前请求。否则,将调用 DefaultAuthenticateScheme 并继续执行管道。

OpenIddictServerAspNetCoreHandler 将调用各种内置处理器(处理请求和响应),处理器将根据上下文处理或跳过与其无关的逻辑。

令牌请求示例:

POST /connect/token HTTP/1.1
Content-Type: application/x-www-form-urlencoded

    grant_type=password&
    client_id=AbpApp&
    client_secret=1q2w3e*&
    username=admin&
    password=1q2w3E*&
    scope=AbpAPI offline_access

此请求将由各种处理器处理。它们将确认请求的端点类型,检查 HTTP/HTTPS,验证请求参数(clientscope 等)是否有效并存在于数据库中,等等。进行各种协议检查。并构建一个 OpenIddictRequest 对象。如果有任何错误,可能会设置响应内容并直接短路当前请求。

如果一切正常,请求将转到我们的处理控制器(例如 TokenController),此时我们可以从 HTTP 请求中获取 OpenIddictRequest 对象。其余处理将基于此对象进行。

检查请求中的 usernamepassword。如果正确,则创建一个 ClaimsPrincipal 对象并返回一个 SignInResult,它使用 OpenIddict.Validation.AspNetCore 认证方案名称,将调用 OpenIddictServerAspNetCoreHandler 进行处理。

OpenIddictServerAspNetCoreHandler 进行一些检查以生成 JSON 并替换 HTTP 响应内容。

ForbidResultChallengeResult 的处理方式同上。

如果您需要自定义 OpenIddict,则需要替换/删除/添加新的处理器,并使其以正确的顺序执行。

请参考: https://documentation.openiddict.com/guides/index.html#events-model

PKCE

https://documentation.openiddict.com/configuration/proof-key-for-code-exchange.html

设置令牌生命周期

更新 AuthServerModule(或者如果没有分层/独立的认证服务器,则更新 HttpApiHostModule)文件的 PreConfigureServices 方法:

PreConfigure<OpenIddictServerBuilder>(builder =>
{
    builder.SetAuthorizationCodeLifetime(TimeSpan.FromMinutes(30));
    builder.SetAccessTokenLifetime(TimeSpan.FromMinutes(30));
    builder.SetIdentityTokenLifetime(TimeSpan.FromMinutes(30));
    builder.SetRefreshTokenLifetime(TimeSpan.FromDays(14));
});

刷新令牌

要使用刷新令牌,它必须得到 OpenIddictServer 的支持,并且应用程序必须请求 refresh_token

配置 OpenIddictServer

有两种方法允许应用程序使用 refresh_token

  • 从 OpenIddictDataSeedContributor,在 CreateApplicationAsync 方法中将 OpenIddictConstants.GrantTypes.RefreshToken 添加到授权类型中:

    await CreateApplicationAsync(
        ...
        grantTypes: new List<string> //混合流
        {
            OpenIddictConstants.GrantTypes.AuthorizationCode,
            OpenIddictConstants.GrantTypes.Implicit,
            OpenIddictConstants.GrantTypes.RefreshToken,
        },
        ...
    

    注意: 如果您已经生成了数据库,则需要重新创建此客户端。

  • 或者从 OpenIddict 管理 UI,编辑您的应用程序并 允许刷新令牌流

openiddict-edit-refresh-token

注意: Angular 应用程序已配置为使用 refresh_token

配置应用程序

您需要请求 offline_access scope 才能接收 refresh_token

Razor/MVC、Blazor-Server 应用程序中,将 options.Scope.Add("offline_access"); 添加到 OpenIdConnect 选项中。这些应用程序模板默认使用 cookie 身份验证,并且默认的 cookie 过期选项设置为:

.AddCookie("Cookies", options =>
{
    options.ExpireTimeSpan = TimeSpan.FromDays(365);
})

Cookie ExpireTimeSpan 会忽略 access_token 的过期时间,如果其设置的值高于 refresh_token 生命周期,那么过期的 access_token 仍然有效。建议保持 Cookie ExpireTimeSpan刷新令牌生命周期 相同,这样新令牌将被持久化到 cookie 中。

Blazor wasm 应用程序中,将 options.ProviderOptions.DefaultScopes.Add("offline_access"); 添加到 AddOidcAuthentication 选项中。

Angular 应用程序中,将 offline_access 添加到 environment.ts 文件中的 oAuthConfig 范围中。(Angular 应用程序已具备此配置)。

迁移指南

从 IdentityServer 逐步迁移到 OpenIddict 指南

在本文档中