c#中使用identityserver必须分层组合:服务端需显式注册addidentityserver()并配置资源与客户端,客户端依角色选用addjwtbearer()(api)、addopenidconnect()(web前端)或addoidcauthentication()(blazor wasm),且issueruri、authority等url必须严格一致。

直接说结论:C# 中使用 IdentityServer 不是“选一种方式”,而是按角色和职责分层组合——IdentityServer4 或 Duende IdentityServer 本身是认证授权服务端,而客户端(ASP.NET Core Web App、Blazor、SPA、Mobile)用的是配套的客户端库,不是“在同一个项目里写五种接入法”。
IdentityServer 服务端必须显式注册 AddIdentityServer()
你不能跳过这一步就“用上 IdentityServer”。哪怕只是内存模式测试,也得调用 AddIdentityServer() 并配置至少一个 ApiResource 和 Client。漏掉 AddIdentityServer() 或没调用 UseIdentityServer(),后续所有中间件(如 AddAuthentication().AddJwtBearer())都拿不到 issuer metadata,会报 InvalidOperationException: No signing credential is configured 或 invalid issuer。
-
AddIdentityServer()必须在Program.cs的服务注册阶段调用,且早于AddAuthentication() - 若用 EF 存储配置(Clients/ApiResources),必须先注册
AddConfigurationStore()和AddOperationalStore(),否则启动时报Unable to resolve service for type 'IConfigurationStore' - 内存模式下,
AddInMemoryIdentityResources()和AddInMemoryApiResources()是必须的;但AddInMemoryIdentityResources()不等于AddIdentityResources()—— 后者是 IdentityServerBuilder 的扩展方法,用于从配置节加载,参数类型不同
客户端用 AddJwtBearer 还是 AddOpenIdConnect?看你是谁
Web 后端 API(比如 ASP.NET Core Web API)用 AddJwtBearer() 验证访问令牌;而需要登录跳转的前端应用(MVC、Razor Pages、Blazor Server)必须用 AddOpenIdConnect(),它负责发起授权码流程、处理回调、管理 Cookie。
- Blazor WebAssembly(WASM)不能用
AddOpenIdConnect(),必须用Microsoft.AspNetCore.Components.WebAssembly.Authentication包里的AddOidcAuthentication(),否则会因 Cookie/CORS 限制静默失败 -
AddJwtBearer()的Authority必须指向 IdentityServer 的根地址(如https://localhost:5001),不是/connect/token或/well-known/openid-configuration;它会自动拼接 discovery endpoint - 如果 IdentityServer 启用了
RequirePkce(默认开启),AddOpenIdConnect()客户端必须设ResponseTypes = "code"且不手动关 PKCE,否则报invalid_request: pkce_not_supported
AddIdentityServerJwt() 是 Blazor Server 的快捷封装,别乱套用
AddIdentityServerJwt() 是 ASP.NET Core 模板为 Blazor Server 自动生成的扩展方法,它内部同时做了两件事:注册 AddAuthentication().AddIdentityServerJwt()(基于 cookie + JWT 回退),又隐式配置了 IdentityServer 客户端。它只适用于 同一解决方案中 IdentityServer 和 Blazor Server 共存 的场景。
- 如果你的 Web API 和 IdentityServer 是分离部署的,绝不能用
AddIdentityServerJwt(),否则会硬编码依赖本地/_configuration/{clientName}endpoint,上线后 404 - 该方法会自动添加
ApiAuthorizationDbContext<tuser></tuser>,若你已用自定义ApplicationDbContext,需手动覆盖或禁用迁移冲突 - 它默认启用
LocalhostRedirectUris白名单,生产环境必须改配置项IdentityServer:Clients:{clientName}:RedirectUris,否则回调失败
用 Duende 替换 IdentityServer4 时,AddIdentityResources() 的配置密钥变了
Duende IdentityServer 6+ 移除了对 identityserver:identity 这类硬编码配置密钥的支持。原来靠 AddIdentityResources(builder, configuration) 自动加载的配置,现在必须显式调用 AddIdentityResources() 并传入 IEnumerable<identityresource></identityresource> 实例,或改用 AddConfigurationStore() 从数据库读取。
- 旧写法:
builder.AddIdentityResources(Configuration)→ 新写法:builder.AddIdentityResources(GetIdentityResources()),其中GetIdentityResources()返回new List<identityresource> { new IdentityResources.OpenId(), new IdentityResources.Profile() }</identityresource> - 若仍想用配置文件驱动,必须自己实现
IConfigureOptions<identityserveroptions></identityserveroptions>,在Configure()里解析Configuration.GetSection("IdentityResources")并注入资源列表 - Duende 默认关闭
EnableCaching,若你依赖内存缓存加速 discovery document,要手动services.AddMemoryCache()并配置options.Caching.Enabled = true
最常被忽略的一点:IdentityServer 的 IssuerUri 必须与客户端看到的 URL 完全一致(协议、域名、端口、路径),哪怕只是开发时用了 https://localhost:5001 而客户端发请求用的是 http://localhost:5000,JWT 验证就会因 invalid_issuer 失败——这个值不会自动从请求头推导,必须显式配置。










