scope是客户端声明的访问权限范围,claims是用户身份携带的属性数据;openiddict不自动映射scope为claims,需手动注入,且scope控制“能访问什么”,claims控制“是谁、有什么属性”。

OpenIddict 里 scope 和 claims 的区别在哪
scope 是客户端请求访问权限时声明的“能力范围”,比如 api.read 或 profile;claims 是用户身份中实际携带的“属性数据”,比如 name、email、role。OpenIddict 不自动把 scope 映射成 claims,也不自动发放 claims —— 它只按你配置的 scope 列表决定是否签发 token,而 claims 必须显式添加到 ClaimsPrincipal 或通过 IAuthorizationService 注入。
常见错误是以为只要在 client 配置了 scopes = ["profile"],token 就会自动包含 name 和 email。不会。必须手动在登录逻辑里把用户信息加进 ClaimsIdentity,或用 AddClaims 扩展方法补全。
- scope 控制“能访问什么”,用于授权决策(如
[Authorize(Policy = "ApiRead")]) - claims 控制“是谁、有什么属性”,用于业务逻辑(如
User.FindFirst("role")?.Value) - OpenIddict 默认只注入
sub、iat、exp等基础 claims,其余全靠你填
如何注册 API 资源(Resource Server)
API 资源不是 OpenIddict 自动识别的,而是靠 AddApiScopes + AddApiResources 显式定义,并在 API 项目中用 AddAuthentication().AddJwtBearer() 验证 token 中的 aud 和 scope。
关键点:API 项目和授权服务器可以分离,但 scope 名称必须完全一致(大小写敏感),且 API 的 audience 必须匹配授权服务器注册的 ApiResources 名称。
- 在授权服务器调用
services.AddOpenIddict().AddServer().AddApiScopes("api.read", "api.write") - 再调用
AddApiResources("my_api", "My API"),其中"my_api"将成为 JWT 的aud值 - 在 API 项目中,
JwtBearerOptions.Audience必须设为"my_api",否则验证失败 - scope 检查需配合策略:如
options.AddPolicy("ApiRead", p => p.RequireClaim("scope", "api.read"))
怎么配置 identity resources(如 profile、email)
identity resources 是 OIDC 标准中预定义的用户属性集合,OpenIddict 本身不内置实现,但允许你用 AddIdentityResources 注册名称,并在 token endpoint 返回时手动注入对应 claims。
例如注册 profile 后,客户端带 scope=profile 请求 token,OpenIddict 不会自动返回 name 或 picture —— 你需要监听 ProcessSignInContext 事件,在签发前把用户数据塞进去。
- 注册:
options.AddIdentityResources("profile", "email", "address") - 监听事件:
options.AddEventHandler<openiddictserverevents.processsignincontext>(...)</openiddictserverevents.processsignincontext> - 在 handler 中判断
context.Request.GetScopes().Contains("profile"),再调用context.Principal.AddIdentityTokenClaim(...) - 注意:这些 claims 只出现在 ID Token(登录响应)中,不出现在 Access Token,除非你额外往 access token 加
为什么 /connect/token 返回的 access_token 没有 scope 字段
OpenIddict 默认不把 scope 写进 access_token payload,它只在 token 的 scope 响应参数里返回(HTTP body 中),这是 OAuth 2.0 规范行为。access_token 是 opaque 或 JWT,JWT 版本默认也不含 scope claim —— 因为 scope 是授权上下文信息,不是资源访问所需的凭证内容。
如果你需要在 API 中读取 scope,有两种方式:
- 解析 JWT 并检查
scopeclaim(需手动添加,OpenIddict 不自动加):在ProcessSignInContext中调用context.Principal.AddAccessTokenClaim("scope", string.Join(" ", context.Request.GetScopes())) - 更推荐的方式:用 policy +
RequireScope("api.read"),它底层从context.User.FindAll("scope")读取,无需改 token 结构 - 切勿依赖 access_token 中是否存在
scope字段做鉴权,应统一走IAuthorizationService或策略机制
最易被忽略的是:scope 名称拼写不一致、大小写错位、API 未正确设置 audience、以及忘记在 ProcessSignInContext 中手动注入 identity claims —— 这些都会导致看似配置完整,实则 token 为空或鉴权失败。










