【免费下载链接】aspnetboilerplate
ASP.NET Boilerplate - Web Application Framework
本文以 ASP.NET Boilerplate 开源仓库中 Identity-Server-vNext.md 文档为骨架,完整讲解如何将 IdentityServer4(2.0+ 版本)集成进基于 ASP.NET Core + Module Zero(Abp.ZeroCore)的启动模板项目,涵盖 NuGet 包安装、模块依赖、Startup 管线配置、IdentityServer 资源与客户端定义、EF Core 持久化改造、JWT 认证中间件接入,以及通过 Console 客户端实测令牌颁发与受保护 API 调用的完整流程。读完本文,你将具备在 ABP 框架中快速搭建一个可签发 access token、支持用户密码模式(Resource Owner Password)与客户端凭证模式的单点登录(SSO)/认证服务器的实战能力。
注意:IdentityServer 已改变其开源许可模型,ASP.NET Boilerplate 官方文档明确建议新项目改用 OpenIddict 集成方案。本文面向需要维护或继续使用 IdentityServer4 集成的既有项目,并会给出两者选型建议。
IdentityServer4 与 ABP 集成的背景
IdentityServer4 是一个开源的 OpenID Connect 与 OAuth 2.0 框架(官方站点 identityserver.io)。将它接入应用后,你的应用可以成为一个认证 / 单点登录(SSO)服务器,并且能够为第三方客户端签发 access token,用于访问受保护的 Web API。
在 ASP.NET Boilerplate 中,Module Zero(Abp.ZeroCore)已经提供了多租户、用户管理、角色管理、权限体系等基础设施;在此基础上叠加 IdentityServer4,即可让 ABP 应用在"业务框架"之上天然拥有标准化的认证授权协议能力。本文描述的集成方式适用于 IdentityServer4 2.0+ 版本,仓库中的 NuGet 包说明(Nuget-Packages.md)进一步指出,带 vNext 后缀的包面向 IdentityServer4 4.x+ 版本。
前置条件
- 已从启动模板创建基于 ASP.NET Core(含 Module Zero)的项目并成功运行,模板说明见 Startup-Template-Core。
- 熟悉 ABP 模块系统(Module System) 的基本用法,因为集成第一步就是添加模块依赖。
- 了解 IdentityServer4 自身的概念(IdentityResource、ApiResource、ApiScope、Client、GrantTypes),本文只讲解与 ABP 集成时额外需要做的事。
安装:两个 NuGet 包的分工
IdentityServer4 与 Abp.ZeroCore 的集成涉及两个 NuGet 包:
| 包名 | 作用 |
|---|---|
| Abp.ZeroCore.IdentityServer4.vNext | 主集成包,提供 AddAbpIdentityServer、AddAbpPersistedGrants 等 ABP 专用扩展方法与模块定义 |
| Abp.ZeroCore.IdentityServer4.vNext.EntityFrameworkCore | EF Core 存储提供程序,用于把授权许可(consent)等数据持久化到数据库 |
由于 EF Core 包已经依赖主集成包,你只需把 Abp.ZeroCore.IdentityServer4.vNext.EntityFrameworkCore 安装到包含 DbContext 的项目(默认模板中是 .EntityFrameworkCore 项目)即可:
Install-Package Abp.ZeroCore.IdentityServer4.vNext.EntityFrameworkCore
在仓库中,该包对应的工程文件位于 src/Abp.ZeroCore.IdentityServer4.vNext.EntityFrameworkCore/Abp.ZeroCore.IdentityServer4.vNext.EntityFrameworkCore.csproj,其工程引用指向 Abp.ZeroCore.EntityFrameworkCore,目标框架为 net9.0,这印证了"EF Core 包依赖主集成包所在的项目链"这一事实。
添加模块依赖
安装完成后,在你的 ABP 模块类(一般是 EntityFrameworkCore 项目的模块)上添加 DependsOn 依赖:
[DependsOn(typeof(AbpZeroCoreIdentityServervNextEntityFrameworkCoreModule))]
public class MyModule : AbpModule
{
//...
}
这样,IdentityServer4 的存储、ABP 集成模块会随应用启动一并初始化。
配置 IdentityServer:与标准用法的差异点
在 Abp.ZeroCore 中使用 IdentityServer4,其整体思路与独立使用 IdentityServer4 基本一致(更完整的机制请查阅 IdentityServer4 官方文档),ABP 集成只增加了少量粘合代码。下面按 Startup 类、资源/客户端配置类、DbContext 三个层面展开。
Startup 类:服务注册与中间件管线
在 ASP.NET Core 的 Startup 类中,需要把 IdentityServer 加入服务集合(Service Collection)与中间件管线(Middleware Pipeline)。与标准 IdentityServer4 用法相比,差异点已高亮标注:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
//...
services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddInMemoryIdentityResources(IdentityServerConfig.GetIdentityResources())
.AddInMemoryApiScopes(IdentityServerConfig.GetApiScopes())
.AddInMemoryApiResources(IdentityServerConfig.GetApiResources())
.AddInMemoryClients(IdentityServerConfig.GetClients())
.AddAbpPersistedGrants<IAbpPersistedGrantDbContext>()
.AddAbpIdentityServer<User>();
//...
}
public void Configure(IApplicationBuilder app)
{
//...
app.UseJwtTokenMiddleware("IdentityBearer");
app.UseIdentityServer();
//...
}
}
在启动模板项目中,代码插入位置如下:
services.AddIdentityServer()放在IdentityRegistrar.Register(services)之后;app.UseJwtTokenMiddleware("IdentityBearer")放在app.UseAuthentication()之后。
AddAbpIdentityServer<User>() 是 ABP 提供的扩展,它会把 ABP 的用户体系(User 实体)与 IdentityServer4 的认证/令牌流程衔接起来——也就是说,密码模式登录时校验的账号正是 Module Zero 管理的用户。
IdentityServerConfig 类:定义身份资源、API 资源与客户端
IdentityServerConfig 用于集中定义身份资源(Identity Resources)、API 资源(API Resources)与客户端(Clients)。最简单的情况下,它可以是一个静态类:
public static class IdentityServerConfig
{
public static IEnumerable<IdentityResource> GetIdentityResources()
{
return new List<IdentityResource>
{
new IdentityResources.OpenId(),
new IdentityResources.Profile(),
new IdentityResources.Email(),
new IdentityResources.Phone()
};
}
public static IEnumerable<ApiScope> GetApiScopes()
{
return new List<ApiScope>
{
new ApiScope("default-api-scope")
};
}
public static IEnumerable<ApiResource> GetApiResources()
{
return new List<ApiResource>
{
new ApiResource("default-api-resource", "Default (all) API")
{
Scopes = { "default-api-scope" }
}
};
}
public static IEnumerable<Client> GetClients()
{
return new List<Client>
{
new Client
{
ClientId = "client",
AllowedGrantTypes = GrantTypes.ClientCredentials.Union(GrantTypes.ResourceOwnerPassword).ToList(),
AllowedScopes = {"default-api-scope"},
ClientSecrets =
{
new Secret("secret".Sha256())
}
}
};
}
}
要点说明:
GetIdentityResources():声明 OpenID Connect 的 OpenId / Profile / Email / Phone 标准身份资源,客户端请求时可携带对应的scope以获取用户身份信息。GetApiScopes()与GetApiResources():定义一个名为default-api-resource的 API 资源,并将其绑定到default-api-scope作用域上;受保护 API 校验令牌时需要声明允许该 scope。GetClients():注册客户端client(密钥为secret的 SHA256 哈希),同时启用ClientCredentials(客户端凭证模式)与ResourceOwnerPassword(密码模式)两种授权类型,允许访问default-api-scope。- 上述资源/客户端均为内存配置(
AddInMemory*),适用于原型与演示;生产环境可替换为 IdentityServer4 的持久化存储。
DbContext 变更:持久化授权许可
AddAbpPersistedGrants() 扩展方法用于把**用户同意响应(consent responses)**保存到持久化存储中。要使用它,YourDbContext 必须实现 IAbpPersistedGrantDbContext 接口:
public class YourDbContext : AbpZeroDbContext<Tenant, Role, User, YourDbContext>, IAbpPersistedGrantDbContext
{
public DbSet<PersistedGrantEntity> PersistedGrants { get; set; }
public YourDbContext(DbContextOptions<YourDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.ConfigurePersistedGrantEntity();
}
}
其中:
IAbpPersistedGrantDbContext接口定义了PersistedGrants这个DbSet<PersistedGrantEntity>;- 必须在
OnModelCreating中调用modelBuilder.ConfigurePersistedGrantEntity()扩展方法,为PersistedGrantEntity配置 EF Core 映射。
不要忘记迁移:这个 DbContext 变更会生成一个新的数据库迁移,请执行:
Add-Migration <YourMigrationName>
Update-Database
关于省略持久化的风险:即使不调用 AddAbpPersistedGrants<YourDbContext>() 扩展方法,IdentityServer4 依然能正常工作——但此时用户同意响应会存储在内存数据存储中,应用重启后即被清空!因此生产环境务必启用 EF Core 持久化。
JWT 认证中间件:保护同一个应用内的 API
如果我们希望客户端与同一个应用进行授权交互(即令牌颁发方与 API 宿主是同一应用),可以使用 IdentityServer 认证中间件(IdentityServer4.AccessTokenValidation)来校验令牌。
首先从 NuGet 安装认证包:
Install-Package IdentityServer4.AccessTokenValidation
然后在 Startup 类中添加认证方案(放在 services.AddIdentityServer() 这行之后):
services.AddAuthentication().AddIdentityServerAuthentication("IdentityBearer", options =>
{
options.Authority = "https://localhost:44388/";
options.RequireHttpsMetadata = false;
});
要点说明:
- 方案名
"IdentityBearer"必须与app.UseJwtTokenMiddleware("IdentityBearer")中传入的名称一致; Authority指向身份服务器地址(此处为本地开发地址https://localhost:44388/,请替换为你的实际站点地址);RequireHttpsMetadata = false允许开发环境下通过 HTTP/自签名 HTTPS 获取元数据;生产环境应保持true并使用 HTTPS。
配置完成后,ABP 的 Web API 控制器与动态 Web API 即可通过该认证方案验证由 IdentityServer 签发的 JWT 令牌。
测试:用 Console 客户端实测完整认证流程
身份服务器就绪后,我们可以创建一个 Console 应用程序作为客户端,走一遍"获取令牌 → 调用受保护 API"的完整流程。
客户端项目准备
- 在解决方案中新建一个 Console Application 项目;
- 添加 IdentityModel NuGet 包:用于创建访问 OAuth 端点的客户端(发现文档、请求令牌等);
- 添加对 Application 层的项目引用:这样客户端可以直接复用应用服务返回的 DTO 类型,实现类型安全的 API 调用;
- 添加 Abp.Web.Common NuGet 包:以便使用 ASP.NET Boilerplate 定义的
AjaxResponse类统一解析服务端响应,避免手工处理原始 JSON 字符串。
完整 Program.cs 代码
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Abp.Application.Services.Dto;
using Abp.Web.Models;
using IdentityModel.Client;
using Newtonsoft.Json;
namespace IdentityServerIntegrationDemo.ConsoleApiClient
{
class Program
{
static void Main(string[] args)
{
RunDemoAsync().Wait();
Console.ReadLine();
}
public static async Task RunDemoAsync()
{
var accessToken = await GetAccessTokenViaOwnerPasswordAsync();
await GetUsersListAsync(accessToken);
}
private static async Task<string> GetAccessTokenViaOwnerPasswordAsync()
{
var disco = await new HttpClient().GetDiscoveryDocumentAsync("https://localhost:44388");
var tokenClient = new HttpClient();
tokenClient.DefaultRequestHeaders.Add("Abp.TenantId", "1");
var tokenResponse = await tokenClient.RequestPasswordTokenAsync(new PasswordTokenRequest()
{
Address = disco.TokenEndpoint,
ClientId = "client",
ClientSecret = "secret",
UserName = "admin",
Password = "123qwe"
});
if (tokenResponse.IsError)
{
Console.WriteLine("Error: ");
Console.WriteLine(tokenResponse.Error);
}
Console.WriteLine(tokenResponse.Json);
return tokenResponse.AccessToken;
}
private static async Task GetUsersListAsync(string accessToken)
{
var client = new HttpClient();
client.SetBearerToken(accessToken);
var response = await client.GetAsync("https://localhost:44388/api/services/app/user/GetAll");
if (!response.IsSuccessStatusCode)
{
Console.WriteLine(response.StatusCode);
return;
}
var content = await response.Content.ReadAsStringAsync();
var ajaxResponse = JsonConvert.DeserializeObject<AjaxResponse<PagedResultDto<UserListDto>>>(content);
if (!ajaxResponse.Success)
{
throw new Exception(ajaxResponse.Error?.Message ?? "Remote service throws exception!");
}
Console.WriteLine();
Console.WriteLine("Total user count: " + ajaxResponse.Result.TotalCount);
Console.WriteLine();
foreach (var user in ajaxResponse.Result.Items)
{
Console.WriteLine($"### UserId: {user.Id}, UserName: {user.UserName}");
Console.WriteLine(JsonConvert.SerializeObject(user, Formatting.Indented));
}
}
}
internal class UserListDto
{
public int Id { get; set; }
public string UserName { get; set; }
}
}
运行前检查清单
- Web 项目必须已启动并正在运行:Console 应用会向 Web 应用发起真实 HTTP 请求;
- 端口必须一致:Console 应用中请求的端口(示例为
44388)必须与你的 Web 应用实际监听端口相同; - 账号必须存在:密码模式使用的
admin / 123qwe是启动模板的默认管理员账号,请按你的实际初始化数据调整; - 多租户头:示例在令牌请求时附加了
Abp.TenantId: 1请求头,这是 ABP 多租户体系(见 Multi-Tenancy)在令牌阶段的典型用法,单租户场景可去掉。
预期执行流程
GetDiscoveryDocumentAsync从身份服务器获取TokenEndpoint等端点信息(基于 OpenID Connect Discovery 协议);RequestPasswordTokenAsync使用client/secret与admin账号密码换取 access token(走 Resource Owner Password 授权模式),并打印令牌的 JSON 详情;GetUsersListAsync携带Bearer令牌调用 ABP 动态 Web APIapi/services/app/user/GetAll;- 用
AjaxResponse<PagedResultDto<UserListDto>>反序列化 ABP 标准响应,输出用户总数与每条用户记录的Id、UserName及完整 JSON。
成功运行后,你将看到控制台依次输出令牌响应 JSON、用户总数以及用户明细,证明"IdentityServer4 签发令牌 → ABP API 校验令牌 → 返回 DTO 数据"整条链路已打通。
许可证变更背景与 OpenIddict 迁移建议
为什么文档推荐新项目使用 OpenIddict
IdentityServer 官方改变了其许可证模型,因此 ASP.NET Boilerplate 文档在本文开头即明确:新项目建议使用 OpenIddict。OpenIddict 旨在为任意 ASP.NET Core 2.1+ 应用提供 OpenID Connect 客户端、服务端与令牌校验支持(ASP.NET 4.6.1+ 也通过 Owin 4.2 集成获得支持)。
仓库中已提供完整的 OpenIddict 集成方案,对应文档见 OpenIddict.md,涉及三个 NuGet 包:
| 包名 | 安装项目 |
|---|---|
| Abp.ZeroCore.OpenIddict | Core 项目,模块依赖 AbpZeroCoreOpenIddictModule |
| Abp.AspNetCore.OpenIddict | Web 项目,模块依赖 AbpAspNetCoreOpenIddictModule |
| Abp.ZeroCore.OpenIddict.EntityFrameworkCore | EntityFrameworkCore 项目,模块依赖 AbpZeroCoreOpenIddictEntityFrameworkCoreModule |
OpenIddict 方案的核心步骤包括:在 DbContext 实现 IOpenIddictDbContext 并在 OnModelCreating 中调用 modelBuilder.ConfigureOpenIddict();在 Web 项目中继承 ABP 提供的 AuthorizeController、TokenController、UserInfoController 泛型控制器;在 Startup.cs 中通过静态注册类完成 OpenIddict 配置。整体思路与本文的 IdentityServer4 集成非常相似:先装包、再加模块依赖、再改 DbContext、再配 Startup。
如何选择
- 新项目:优先采用 OpenIddict 集成,这是 ASP.NET Boilerplate 官方推荐的现行方案;
- 既有项目:若已基于
Abp.ZeroCore.IdentityServer4.vNext集成 IdentityServer4,可继续沿用本文配置维护,同时规划向 OpenIddict 迁移; - 包版本区分:根据 Nuget-Packages.md 的说明,
Abp.ZeroCore.IdentityServer4(无 vNext 后缀)面向早期 IdentityServer4 版本,Abp.ZeroCore.IdentityServer4.vNext面向 IdentityServer4 4.x+,两个主包分别对应各自的 EntityFrameworkCore 存储包,选择时务必与所用 IdentityServer4 大版本匹配。
集成要点速查
| 步骤 | 关键操作 | 位置 |
|---|---|---|
| 1. 装包 | Install-Package Abp.ZeroCore.IdentityServer4.vNext.EntityFrameworkCore | EntityFrameworkCore 项目 |
| 2. 模块依赖 | [DependsOn(typeof(AbpZeroCoreIdentityServervNextEntityFrameworkCoreModule))] | 模块类 |
| 3. 服务注册 | services.AddIdentityServer().AddAbpPersistedGrants<...>().AddAbpIdentityServer<User>() | ConfigureServices,紧跟 IdentityRegistrar.Register(services) 之后 |
| 4. 中间件 | app.UseJwtTokenMiddleware("IdentityBearer"); app.UseIdentityServer(); | Configure,紧跟 app.UseAuthentication() 之后 |
| 5. 资源/客户端 | 静态类 IdentityServerConfig 提供 GetIdentityResources/GetApiScopes/GetApiResources/GetClients | 任意合适位置 |
| 6. DbContext | 实现 IAbpPersistedGrantDbContext,OnModelCreating 中调用 ConfigurePersistedGrantEntity(),然后 Add-Migration + Update-Database | EntityFrameworkCore 项目 |
| 7. JWT 校验(可选) | Install-Package IdentityServer4.AccessTokenValidation,注册 IdentityBearer 认证方案 | Startup |
| 8. 客户端测试 | Console 应用 + IdentityModel + Application 层引用 + Abp.Web.Common | 解决方案内 |
延伸阅读
- OpenIddict 集成(新项目推荐方案)
- Module Zero 启动模板(ASP.NET Core MVC)
- ABP 模块系统
- Module Zero NuGet 包一览
- ABP Web API 控制器与动态 Web API
- 多租户机制
【免费下载链接】aspnetboilerplate
ASP.NET Boilerplate - Web Application Framework
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



