资讯详情

从零搭建OAuth2.0认证授权中心:IdentityServer4实战教程

📅 2026/10/19 11:29:15 | 华诺云谱 👁 阅读
从零搭建OAuth2.0认证授权中心:IdentityServer4实战教程
先说一下IdentityServer4 这套东西在 .NET 生态里虽然已经进入了“维护模式”但存量项目实在太多而且它背后的 OAuth 2.0 / OpenID Connect 思想完全没过时。我之前帮几家公司接过老的 IdentityServer4 项目也自己从零搭过整套访问控制链路这套实践路径对现在用 .NET 6/7/8 重构 API 网关、统一认证中心依然有很强的参考价值。我写的这篇教程不是照搬官方文档而是把我实际搭这套东西的完整过程、踩过坑、还有排查思路都整理出来。不管你是刚接触认证授权的新手还是接了一个老项目需要理清头绪的开发者这篇内容都能给你一条比较清晰的路线。1. 为什么需要一套独立的认证授权中心先聊一个根本问题我们做 API 和 Web 应用到底防的是什么最常见的安全漏洞就是“信任了不该信任的请求来源”。比如你做了一个订单接口直接让浏览器把用户 ID 传过来然后后台拿着“用户传入的 ID”去查数据库、改数据。这种设计等于把后门焊死在门框上——任何人都可以伪造请求改一下参数就变成别人了。另一个常见问题是“各系统各自为政的 Session 认证”。用户登录 A 系统有一个 Session登录 B 系统又有一个 Session两边互不相通。想搞个单点登录SSO要么复制 Session要么让用户在多个系统之间重复登录。到了多系统架构的时候这种模式几乎是灾难。而 IdentityServer4 解决的问题就是把“认证”和“授权”这两个动作从业务系统里抽离出来放到一个独立的中枢里。它做的事情本质上就三件确认“你是谁”认证Authentication决定“你能访问什么”授权Authorization把这些结论打包成标准令牌交给各个 API 和 Web 应用去校验Token 发放与验证这套模型对应的是 OAuth 2.0 协议。OAuth 2.0 定义了令牌Token的发放方式、使用方式、校验方式但它没有规定令牌长什么样。而 IdentityServer4 同时支持 OpenID Connect简称 OIDC这是 OAuth 2.0 之上的一个身份认证层可以让客户端拿到用户的身份信息Identity而不仅仅是访问权限。IdentityServer4 默认签发的就是 JWT 格式令牌JSON Web Token把用户信息和权限声明用 JSON 编码、加密签名放到令牌里面。API 端拿到令牌后只需要验签不需要每次去认证中心查一次数据库扩展性好很多。所以当你面对以下任何一种情况时引入一套独立的认证授权中心都是值得的你有两个以上的系统希望用户登录一次就能访问所有系统你的 API 会被多个客户端调用Web 前端、手机 App、第三方系统你不想在每一个 API 项目里复制粘贴一套“用户登录验证”逻辑你希望 API 和 Web 端彻底解耦让 API 只关心“令牌是否合法”不用关心“用户名密码怎么验证”IdentityServer4 正是在 .NET Core 时代解决这些问题的成熟答案。下面的实操我会用一个最典型的组合来演示授权服务器IdentityServer4 受保护的 APIWeb API MVC 客户端Web 应用这个组合基本覆盖了日常开发里最常见的几种接入形态。2. 方案选型的两种经验视角在实际项目中我一直建议团队在动工之前先想清楚一件事我们是真的需要一个独立认证中心还是先做一个库把认证逻辑封装一下就行这个决定会直接影响架构的复杂度。2.1 什么时候必须上独立认证中心判断标准很简单有没有多个开发团队或者多个服务在共享身份体系比如订单服务、用户服务、支付服务是三个团队在维护每个服务都要求调用方带“登录凭证”。如果每个服务各自解释 Session迟早会出现逻辑不一致。这时候你必须有一个中心化的令牌发放服务让所有服务共用同一套验签机制和同一个公钥来源。我在一个项目里见过最头疼的情况两个服务各自实现了 JWT 校验但用的密钥一个是 AES 对称密钥一个是 RSA 非对称密钥。然后前端拿到 A 服务的令牌去调 B 服务B 根本不认识。最后花了一个多星期统一密钥体系期间线上问题不断。所以早期就把认证中心独立出来本质上是在给未来省事。2.2 与手写 JWT 中间件的取舍也有人问过我既然 JWT 校验在 .NET 里就几行代码为什么还需要 IdentityServer4 这种框架我的观点是如果你的系统就是一个单体应用自己手写一个 JWT 签发和校验中间件完全够用甚至更轻量。但如果你的系统会有多个客户端、多种授权模式授权码、客户端凭证、刷新令牌、需要支持外部身份提供商登录那手写这套东西的成本就高了。IdentityServer4 的价值在于它把 OAuth 2.0 里最难的协议流程比如授权码流程中的 redirect_uri 校验、state 防 CSRF、PKCE 验证都实现好了。这些都是安全敏感的点自己手写出 bug 的代价远大于引入框架的成本。2.3 版本选型上的特殊提醒这里要特别提醒一句IdentityServer4 已经不再发布新功能官方只维护安全补丁。如果你要启动一个全新的 .NET 8 项目更合适的选择是它的继任者——一个基于 .NET 8 的新版本框架或者直接用其他成熟方案。但这不等于 IdentityServer4 没有学习价值OAuth 2.0 / OIDC 协议在各大语言里的落地形态大同小异搞懂 IdentityServer4 的配置模型再上手新框架基本是无痛迁移。因此这篇教程里的配置思路和排障逻辑放到任何一套 OIDC 实现里都是通用的。3. 搭建授权服务器核心配置逐个拆解现在开始动真格的。授权服务器的搭建核心不在代码量而在对“客户端Client”、“范围Scope”、“资源Resource”这三个概念的理解。这一节我会把配置逐行拆开讲。3.1 创建项目并安装服务端包我用一个空的 ASP.NET Core 项目来做演示。假设项目名是 AuthServer目标框架我建议你用 .NET 6 或 .NET 8 的 LTS 版本。需要安装的主包是IdentityServer4如果你需要把客户端信息、用户信息持久化到数据库还要装IdentityServer4.EntityFramework用于数据库持久化IdentityServer4.AspNetIdentity用于集成 ASP.NET Core Identity不过这一篇先用内存配置来演示把流程跑通是第一步。修改 Startup 或者顶层语句里的服务注册代码加上services.AddIdentityServer() .AddInMemoryIdentityResources(Config.IdentityResources) .AddInMemoryApiScopes(Config.ApiScopes) .AddInMemoryClients(Config.Clients) .AddTestUsers(TestUsers.Users);这段代码看起来简单但每一行都对应着一个核心配置。下面我逐个说清楚。3.2 Identity 资源用户身份信息的“白名单”Identity 资源描述的是“身份令牌里可以携带哪些用户信息”。有过 OAuth 经验的人知道令牌里塞的信息越少越安全所以 OIDC 搞了一个“作用域Scope”机制客户端想要哪种信息就在请求令牌的时候显式声明。IdentityServer4 内置了两个最常用的 Identity 资源public static IEnumerableIdentityResource IdentityResources new[] { new IdentityResources.OpenId(), // 必须存在表示客户端请求的是 OIDC 身份认证 new IdentityResources.Profile(), // 可携带用户昵称、头像、姓名等资料 };OpenId 是所有 OIDC 流程的必选项没有它IdentityServer4 根本不会走身份认证流程。Profile 则是“可选白名单”客户端申请了这个作用域令牌里才有用户资料。3.3 API 范围访问 API 的“权限门票”ApiScope 用来声明“系统里有哪些可被访问的 API 权限域”。举个例子你有一个订单服务和一个商品服务就可以定义两个范围new ApiScope(order_api, 订单服务访问权限), new ApiScope(product_api, 商品服务访问权限)客户端请求令牌的时候只能申请白名单里注册过的范围。当它拿着令牌去访问某个 API 时API 会检查令牌里是否包含自己对应的 Scope。如果客户端没申请这个 ScopeAPI 就直接拒绝。一个常见的设计困惑是Scope 和 Role角色有什么区别我的理解是Scope 是粗粒度的客户端级权限决定“这个应用能不能调这个 API”Role角色则是细粒度的用户级权限决定“这个用户能不能执行某个操作”。IdentityServer4 令牌里的 claim 可以同时携带 Scope 和 RoleAPI 端既要验 Scope 又要验角色两者配合使用。3.4 客户端配置每个接入方的“身份证”客户端代表一个具体的应用比如 MVC 网站、SPA 单页应用、手机 App。每个客户端都有自己独立的 ClientId 和密钥。下面是一个典型的 MVC 客户端配置new Client { ClientId mvc_client, ClientSecrets { new Secret(mvc_secret.Sha256()) }, AllowedGrantTypes GrantTypes.Code, RequirePkce true, RedirectUris { https://localhost:5002/signin-oidc }, PostLogoutRedirectUris { https://localhost:5002/signout-callback-oidc }, AllowedScopes { openid, profile, order_api }, AccessTokenLifetime 3600, }逐项解释一下ClientId 和 ClientSecrets是客户端的身份凭证。跟用户密码类似但这是应用级别的。AllowedGrantTypes这是最关键的一项决定客户端用哪种 OAuth 流程申请令牌。 mvc_client 用的是授权码模式Authorization Code Flow这是 OIDC 里 Web 应用最推荐的模式因为用户密码不会直接暴露给客户端而是通过浏览器跳转到授权服务器登录登录成功后授权服务器把“授权码”返回给客户端客户端再用授权码换令牌。- RequirePkce建议所有客户端都开启 PKCE。它的作用是防止授权码被拦截后攻击者拿着授权码去换令牌。开启后客户端在发起认证请求时会生成一个随机密文换令牌时必须提供对应的校验值授权服务器会比对不匹配就拒绝。 - RedirectUris这是个安全回环地址授权服务器只认这个白名单里的回调地址。这个是 OAuth 里最容易配错的地方我后面会专门讲。 - AllowedScopes决定这个客户端能申请哪些权限越少越好。 - AccessTokenLifetime访问令牌的存活秒数。3600 也就是 1 小时。业务上要平衡安全和性能太短客户端频繁刷新太长令牌泄露后的风险窗口大。做内部系统我一般建议 3600 到 7200开放平台类应用建议 1800 左右。 ### 3.5 启动授权服务器 在 Startup.cs 或顶层语句里确保请求管道中调用了 csharp app.UseIdentityServer();然后启动项目浏览器访问https://localhost:5001/.well-known/openid-configuration如果能看到一串 JSON 配置信息说明授权服务器已经成功启动。这个 JSON 文档叫“发现文档”它向所有客户端公开了一些必要的元数据比如令牌端点地址、授权端点地址、支持的签名算法等。很多客户端中间件就是靠读这个文档自动完成配置的。4. 接入受保护的 API 资源JWT 校验原理与配置授权服务器搭好了接下来把 API 保护起来。实际上在纯 API 场景下IdentityServer4 只负责“发令牌”API 端需要自己校验令牌。这部分的体验好坏直接影响你是否愿意继续用这套方案。4.1 认证中间件配置在 API 项目里安装Microsoft.AspNetCore.Authentication.JwtBearer然后在服务注册处services.AddAuthentication(Bearer) .AddJwtBearer(Bearer, options { options.Authority http://localhost:5000; options.RequireHttpsMetadata true; options.Audience order_api; }); services.AddAuthorization();这里我会重点解释三个参数Authority告诉 API 从哪里获取授权服务器的公钥信息。JwtBearer 中间件启动后会自动请求{Authority}/.well-known/openid-configuration然后从里面找到 JWKSJSON Web Key Set公钥集合用来验签令牌。这就是“无需每次调用认证中心”的关键API 只依赖公钥验签不依赖认证中心的网络可达性。即使认证中心临时挂了已经发出的令牌仍然可以被 API 验证通过。Audience令牌的“受众”。客户端申请令牌的时候带上 scopeIdentityServer4 在签发令牌时会根据 scope 映射出 aud 声明。API 端配置的 Audience 必须和令牌里的 aud 匹配不然验签通过也会报“无效受众”。RequireHttpsMetadata生产上建议设为 true。这要求授权服务器必须是 HTTPS 地址防止令牌在传输过程中被窃取。本地开发时如果用了 HTTP可以先设 false但上线前必须改回来。4.2 使用策略Controller 层的保护配置好认证之后在你需要保护的 API 控制器上加上[Authorize]特性就行。[Authorize] [ApiController] [Route(api/orders)] public class OrdersController : ControllerBase { [HttpGet] public IActionResult GetOrders() { var userId User.FindFirst(sub)?.Value; // 业务逻辑... } }令牌里最主要的一个声明是sub它表示用户的唯一标识。业务系统拿这个 sub 去对应自己的用户 ID而不是自己去解析用户名密码。这也是一个设计要点业务系统不存密码、不验证密码认证这件事完全交给授权中心。4.3 细粒度权限控制怎么做仅加[Authorize]只是第一步它只保证“有合法令牌”。实际业务里我们经常需要“有令牌 特定角色”才能访问。这个可以在 API 里用策略实现services.AddAuthorization(options { options.AddPolicy(OrderAdmin, policy policy.RequireClaim(role, order_admin)); });控制器上用[Authorize(Policy OrderAdmin)]很多团队会纠结“角色信息是从哪里加到令牌里的”。答案是在授权服务器里配置。IdentityServer4 在用户登录成功后可以自定义 Profile Service从用户表或者权限表里读取角色塞进令牌。这样 API 端就只需要解析令牌权限数据天然统一。我强烈建议不要把大量业务 permission 全塞进 JWT。JWT 一旦发出内容就固定了直到过期前无法单独撤销某一个自定义 claim。所以 JWT 里只放“不易变化的静态信息”比如用户 ID、姓名、角色那些动态权限比如某个用户在某篇文章下的权限应该放到 API 端数据库里实时查询不要做成 claim。5. Web 应用接入授权码流程完整走一遍Web 应用接入的方式和 API 不同。API 是无状态的Web 应用通常还需要保持登录会话。OIDC 的经典做法是用 Cookie 保存登录状态用授权码模式获取令牌。5.1 MVC 客户端配置在 MVC 项目里安装Microsoft.AspNetCore.Authentication.OpenIdConnect服务注册services.AddAuthentication(options { options.DefaultScheme Cookie; options.DefaultChallengeScheme oidc; }) .AddCookie(Cookie) .AddOpenIdConnect(oidc, options { options.Authority http://localhost:5000; options.ClientId mvc_client; options.ClientSecret mvc_secret; options.ResponseType code; // 授权码模式 options.SaveTokens true; // 把访问令牌保存到 Cookie options.Scope.Add(order_api); });这段配置的逻辑是默认的认证方案是 Cookie。也就是说当用户登录后MVC 应用把用户的身份打包进一个加密 Cookie后续每次请求直接用 Cookie 识别身份不需要再去授权服务器验证。当用户未登录时MVC 应用会触发 Challenge将浏览器重定向到授权服务器的登录页面。这个过程是MVC 应用把用户引导到授权服务器的登录页用户在授权服务器上登录并确认授权授权服务器返回一个授权码到 RedirectUris 指定的地址然后 MVC 应用后端拿着授权码去令牌端点换取访问令牌和 ID TokenID Token 里的用户信息会被解包并写入 Cookie。SaveTokens 决定要不要把访问令牌存进 Cookie。如果你后续要用这个令牌去调用受保护的 API就必须开启并在代码里读取 HttpContext.GetTokenAsync(access_token)。如果不调用 API可以不存减少 Cookie 体积。5.2 登录与登出流程登录操作很简单[HttpPost] public IActionResult Login() { return Challenge(new AuthenticationProperties { RedirectUri / }, oidc); }登出则稍微绕一点因为你要通知授权服务器“这个会话已经作废”而不仅仅是清理本地的 Cookie。我一般这样写[HttpPost] public async TaskIActionResult Logout() { await HttpContext.SignOutAsync(Cookie); await HttpContext.SignOutAsync(oidc, new AuthenticationProperties { RedirectUri / }); return Redirect(/); }第一行SignOutAsync(Cookie)清除本地会话第二行是通知授权服务器清除单点登录会话。如果漏掉第二行用户回到登录页时会发现“我没输入密码直接就登录了”因为授权服务器那里的会话还活着。这是新手最容易忽略的一个点。5.3 访问受保护 API 的完整链路当 MVC 客户端要调用受保护 API 的时候流程是从 Cookie 里取出访问令牌access_token把令牌放到 HTTP 请求的 Authorization 头里Authorization: Bearer tokenAPI 服务接收到请求后验签、校验aud、校验过期时间通过后执行业务逻辑返回数据在 .NET 里调用 API 的时候很多项目用 HttpClient 封装但每次都要手动写 Header 有点烦。我建议封装一个专门的 API 客户端类统一在内部读取令牌并设置请求头。一个小技巧是注册IHttpContextAccessor然后在封装类里注入这样可以拿到当前 HttpContext 中保存的令牌。如果令牌过期了还可以先刷新令牌然后重新调用 API。关于刷新令牌我会在下一节展开。6. 令牌过期与刷新机制不打断用户体验的关键访问令牌只有一个小时有效期。如果用户在页面上待了一个半小时重新点按钮时发现接口报 401体验非常差。所以刷新令牌Refresh Token是生产环境必备的一个配置。6.1 刷新令牌的配置与代码在客户端配置里加一行AllowedGrantTypes GrantTypes.CodeAndRefreshToken,同时可以调整刷新令牌的有效期默认是 30 天我个人觉得如果系统安全性要求高可以缩短到 7 天甚至更短AbsoluteRefreshTokenLifetime 604800, // 单位秒这里是 7 天 SlidingRefreshTokenLifetime 86400, // 滑动过期每次用刷新令牌换新令牌会重置这个时间 RefreshTokenUsage TokenUsage.ReUse, // 是否允许刷新令牌重用再补充说明一下刷新逻辑里一个容易踩坑的点。当客户端在令牌快过期时需要拿着 refresh_token 去换取新令牌拿到新的 access_token 和新的 refresh_token 后必须把新的 refresh_token 也更新回存储。如果你存到 Cookie 里就要重新写 Cookie如果你存到数据库里就要更新数据库记录。很多问题都出现在“只更新了 access_token没有更新 refresh_token”结果旧的 refresh_token 一旦过期或撤销用户就彻底掉线。6.2 内存测试用户的体验现在项目里用的是AddTestUsers登录页会直接使用内存里的用户。真实项目一定要换成数据库 ASP.NET Core Identity。不过在演示阶段这个功能确实方便不需要建数据库不需要管密码哈希改一下内存列表就能测试不同用户。我建议在开发阶段给测试用户的角色信息加上足够多的组合方便测试权限策略。比如加一个“管理员”和一个“普通用户”这样测试[Authorize(Policy OrderAdmin)]时可以立刻看出策略是否正确。7. 实测最容易踩的 6 个坑及解决方案作为一篇实践教程光把正向流程写完是不够的。这一节我总结了自己在实际项目里遇到的高频问题按“问题现象、原因分析、解决方案”三步来梳理。7.1 访问授权服务器时返回 404现象浏览器访问/.well-known/openid-configuration返回 404。原因请求管道里没有调用app.UseIdentityServer()或者这个调用放到了路由映射之后。解决把UseIdentityServer()放在UseRouting()之后、UseEndpoints()之前。7.2 登录页面能打开但登录后跳回本地项目时报“redirect_uri 不匹配”这是授权码模式下我见过最多的问题。原因是客户端发起的回调地址和授权服务器注册的 RedirectUris 不完全一致。哪怕少了最后一个斜杠或者 https 写成了 http都会校验失败。解决对比三个地方——客户端中间件配置里的RedirectUri或者options.Events.OnRedirectToIdentityProvider里的地址、浏览器地址栏实际跳转地址、授权服务器Clients里的RedirectUris值。三者必须逐字符一致。另外还要注意一点本地开发时如果用了不同的端口RedirectUris也要跟着改。很多团队用 Git 管理配置开发环境大家端口不一样结果每次拉代码都要改本地端口很麻烦。建议把端口配置放到appsettings.json里不要硬编码。7.3 Claim 类型被自动替换导致取不到角色值在 .NET 的 JWT 中间件里默认会做 claim 映射把 JWT 里的role映射成http://schemas.microsoft.com/ws/2008/06/identity/claims/role。如果你用User.IsInRole(admin)判断但令牌里根本没有这个映射后的类型判断就会失败。解决在 JwtBearer 配置里关掉自动映射options.MapInboundClaims false;或者用自定义的JwtSecurityTokenHandler.InboundClaimTypeMap.Clear()。这个坑非常隐蔽查起来很浪费时间。我建议在写 JWT 校验的第一天就把自动映射关掉统一使用 JWT 原生 claim 名称。7.4 API 返回 401但授权服务器日志显示令牌已经签发这种情况十有八九是Audience不匹配。我的排查步骤是先用在线 JWT 解码工具把 token 解出来看一眼确认里面的aud声明。和 API 配置里的Audience变量比对。不一样就统一掉。这里再补充一个容易忽略的点IdentityServer4 的 scope 名称和 aud 名称默认是同一个值。你配置ApiScope(order_api)的时候生成的aud就是order_api。但很多人在 API 端把Audience写成项目名或者域名就对不上了。这也是高频率错误。7.5 CORS 配置导致前端调用 API 失败纯 Web API 加上身份认证之后还有一个跨域问题。如果前端跑在http://localhost:5002API 跑在http://localhost:5001浏览器会先发一个 OPTIONS 预检请求然后才发真正的请求。预检请求没有 Authorization 头如果服务端不允许跨域请求就挂了。解决在 API 里配置 CORS并正确设置来源白名单services.AddCors(options { options.AddPolicy(AllowFrontend, policy { policy.WithOrigins(http://localhost:5002) .AllowAnyHeader() .AllowAnyMethod(); }); });然后在管道里app.UseCors(AllowFrontend);并且要确保UseCors在UseAuthentication之前调用。顺序错了也会出莫名其妙的 500 错误。7.6 HTTPS 证书问题导致授权服务器重定向失败本地开发用localhost时IdentityServer4 默认要求 HTTPS。如果你的机器证书不受信任或者端口没有正确配置 HTTPS授权服务器登录成功后重定向会失败。解决在appsettings.json里设置IdentityServer: { IssuerUri: http://localhost:5000 }同时把 JwtBearer 的RequireHttpsMetadata在开发环境临时设为 false。这只是开发阶段调试手段上线必须用 HTTPS。8. 授权服务器与 API、Web 应用之间的边界划分最后我想聊聊这套架构的“边界感”。很多团队把认证、授权、业务逻辑全部混在一个项目里改写时牵一发动全身。把边界划清楚问题定位会高效很多。我总结的边界划分是这样授权服务器只管“确认你是谁、你能访问什么”。里面不写业务代码不访问业务数据库。API 资源只管“验证令牌是否有效、提取用户 ID、做业务逻辑”。不验证用户名密码不存令牌。Web 客户端只管“引导用户登录、保存 Cookie、调用 API”。不验证密码不做权限判断。这条边界一旦建立后续加新系统就非常顺滑。新 API 只需要在授权服务器里加一个 ApiScope再在 API 项目里配置同一套 JwtBearer 参数就能即刻接入现有的身份体系。新 Web 应用也只需要注册一个新的 ClientId、授权服务器加一行 RedirectUris就能共享登录状态。我个人在设计的时候还会做另一个决定把授权服务器的数据访问持久化放到数据库但要跟业务系统的数据库分开。身份库和业务库拆开好处是身份库的表结构完全由授权服务器管理不跟业务纠缠坏处是多一个数据源。但对中大型系统来说身份库独立是一个值得长期坚持的原则。9. 从开发到生产的几个关键建议9.1 开发环境与生产环境的配置隔离开发环境用内存配置、临时开发签名密钥Developer Signing Credential很方便。但生产环境一定要切换成正式配置客户端信息和用户信息存数据库我觉得首选是 SQL Server 或 PostgreSQL签名密钥用正式证书而不是临时生成的密钥文件HTTPS 强制开启IdentityServer4 的签名私钥一旦丢了想换新证书所有客户端的发现文档元数据会变化API 端的旧令牌会因为验签失败全部失效。因此证书换发要安排在特定维护窗口并且要预先把新证书信息推到各 API 端。我记得有次运维同事把证书直接替换了没有通知 API 端更新公钥导致线上持续了十几分钟的 401 潮。后来我们定了一个流程证书到期前一个月准备新证书先在测试环境验证一次完整换发流程。9.2 日志与可观测性IdentityServer4 有比较详细的日志输出。在生产环境我把 IdentityServer 的日志级别调到 Information并且把与 Security 相关的事件单独采集。特别是失败登录、令牌换取失败这类事件必须能通过日志中心查到。还有一个经验给每个客户端分配独立的事件前缀或者日志标签排障时按 ClientId 过滤效率会高很多。9.3 性能提示IdentityServer4 本身是无状态的令牌验签都在 API 端完成所以它的性能瓶颈主要在令牌发放接口。正常情况下这个接口接收客户端提交的授权码或重定向然后返回令牌。由于它有内存存储和本地签名单机性能足够支撑一般规模的业务。真正要注意的是数据库连接池和令牌签名的 CPU 开销不要在一个请求里做太多次令牌签发。如果有一天流量大到授权中心成为瓶颈可以考虑横向扩展多实例因为无状态共享数据库扩展起来相对简单。不过一般自用系统到不了这一步。10. 写在最后一点经验心得我在实际项目里维护这种认证授权架构已经有好几年了最大的感受是IdentityServer4 这套方案的强大之处不在于某个单点功能而在于它强制你思考“身份认证”这个环节的边界。即使后来项目重构我从 IdentityServer4 迁移到了别的身份认证框架当年的协议理解、配置思维、排障直觉依然完全适用。如果你正在考虑要不要在自己的系统里引入一套认证中心我的建议是如果只是写一个后端接口给自家前端用那确实可以不必上这套框架手写 JWT 校验足够了。但如果你预计系统会变多、客户端会变多、权限逻辑会变复杂那早点把认证中心独立出来可能是一个比较值得的投资。这里也提醒一下本篇使用的是内存配置所有数据重启即消失仅供学习流程。生产级部署请把客户端、资源、用户全部持久化并配合正式的证书管理流程。遇到问题优先看授权服务器的日志找出日志里出错的请求路径和客户端 ID大部分问题都能靠日志里的线索定位到根因。我在实际使用中发现把这一整套流程完整落过一次地之后再去学习其他语言的 OIDC 解决方案会轻松很多因为协议层的东西是共通的。希望这篇教程能帮你少走一些弯路。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑