前言
1.配置服务认证授权
订单服务(Ordering.API)配置了认证授权,所以我们使用Scalar调试接口的时候也需要认证服务(Identity.API)颁发的token,上面的测试就是401无权限
首先我们再回忆下我们认证授权配置了那些:
- 认证服务(
Authority):我们本地启动的Identity.API,其他服务认证授权配置Identity.API的地址即可。 - 使用
Https协议获取认证中心(Authority)元数据(RequireHttpsMetadata):原来这里是false,访问不验证https,为了多学习我们设置为true,本身Identity.API启动就是使用的https协议 - 订阅人(
Audience):确保认证服务Identity.API颁发的token是发给我的(订单服务),就是我们在appsettings.json中配置"Audience": "orders"。简单理解:什么服务就配置什么服务的标识,但是认证服务同时也要有此标识。确保这个Token是发给当前 API 的,而不是其他服务。验证签发token的aud。 - 签发者(
Issuers):确保Token是由受信任的认证中心签发。验证签发token的iss。

还需要再回忆一下认证服务(Identity.API)中的客户端配置,找到orderingswaggerui配置

然后我们启动认证服务,在..\eShop\src\Identity.API目录下运行以下命令:
dotnet run --urls https://localhost:5243/

2.配置隐式授权(Implicit)
启动订单服务(Ordering.API),打开Scalar,然后配置好Client ID和Scopes,之后点击Authorize

提示我们错误的回调地址(Invalid redirect_uri)

再回到认证服务(Identity.API)的Config配置中,简单了解一下隐式授权模式(Implicit Grant Type)
Implicit Flow:响应类型直接把
access_token(以及可选的id_token)返回给浏览器。常用于早期的单页应用(SPA)、Swagger UI、Scalar 等纯前端客户端,不需要/也无法安全保存客户端密钥(client secret)。特点:
- 不使用客户端密钥(client secret);
- Token 直接通过 URL fragment (
#access_token=...) 返回给浏览器;- 通常不会返回 refresh_token(为避免长期泄露风险);
- 更容易实现,但安全性低于 Authorization Code + PKCE。
所以我们需要配置回调地址,我们配置Scalar的地址,有v1/v2俩个版本的地址:
# ehsop没有配置configuration["OrderingApiClient"],这个返回的是null
# 我们要配置完整地址
RedirectUris = { $"{configuration["OrderingApiClient"]}/swagger/oauth2-redirect.html",$"http://localhost:5224/scalar/v1",$"http://localhost:5224/scalar/v2"
},

配置完回调地址后,再次启动项目,打开Scalar,设置Client ID和Scopes,然后点击Authorize

已经成功获取token,可以点开右边小眼睛图标查看token

点开/api/orders接口测试一下,返现还是返回错误:Bearer error="invalid_token", error_description="The audience 'empty' is invalid"
token中的audience(订阅人)不对

复制获取的token到https://www.jwt.io/中看看

我们在配置AddJwtBearer需要验证签发者(Issuers)和订阅人(Audience),token中没有订阅人(aud)

知道原因了,就在orders的API服务配置授权范围Scopes
new ApiResource("orders", "Orders Service"){Scopes = { "orders" }
}

重新启动认证服务(Identity.API)(有时候需要关闭cmd,重新输入命令启动),再次测试接口,发现请求状态200

通过https://www.jwt.io/解密token,发现已经有了aud
以下几个字段是比较重要的字段,需要留意下:
| 字段 | 英文全称 | 中文解释 |
|---|---|---|
| iss | Issuer | 签发者:表示令牌由谁颁发。这里是授权服务器(IdentityServer)的地址,即 "https://localhost:5243"。API 服务会通过它来验证 token 来源是否可信。 |
| aud | Audience | 受众(目标服务):表示这个令牌是发给哪个 API 的。这里是 "orders",说明这个 token 只能访问名为 orders 的服务。 |
| scope | Scopes | 授权范围:描述 token 拥有哪些访问权限。这里只有 "orders",即允许访问订单服务对应的资源。 |
| client_id | Client Identifier | 客户端 ID:标识是谁请求了这个 token。这里是 "orderingswaggerui",说明是 Swagger UI 这个客户端发起的授权请求。 |
| sub | Subject | 用户唯一标识:表示这个 token 属于哪个用户。通常是用户 ID(GUID)。例如 "473aebe2-7d91-4d99-a4e0-3fcfd0764061"。 |
{"iss": "https://localhost:5243", "aud": "orders","scope": ["orders"],"client_id": "orderingswaggerui","sub": "473aebe2-7d91-4d99-a4e0-3fcfd0764061"
}

有时候没有登录,是因为IdentityServer的Cookie缓存时间较长,可以主动清除Cookie缓存(鼠标右键)

但是IdentityServer弹窗没有弹出授权,这就需要我们在配置RequireConsent
RequireConsent = true, // 强制用户在授权页面确认 scopeRequirePkce = true, // 可选,增加安全性,SPA推荐开启

清除Cookie缓存(鼠标右键)

重新启动认证服务(Identity.API),再次Authorize时,输入完用户密码就需要授权Scope

3.隐式授权流程(Implicit)
首先查看OpenAPI 规范(Scalar 用)中 OAuth2 安全认证机制的定义:本 API(订单服务) 使用 OAuth2 的隐式授权模式,通过认证服务器 https://localhost:5243 登录获取访问令牌,以访问 orders 资源范围的受保护接口。

关闭认证服务(Identity.API),然后再次点击authorize,我们查看Scalar如何请求认证服务(Identity.API)的
# redirect_uri加密了
https://localhost:5243/connect/authorize?response_type=token&redirect_uri=http%3A%2F%2Flocalhost%3A5224%2Fscalar%2Fv1&client_id=orderingswaggerui&state=7b7rbpap&scope=orders# 解密后
https://localhost:5243/connect/authorize?response_type=token&redirect_uri=http://localhost:5224/scalar/v1&client_id=orderingswaggerui&state=7b7rbpap&scope=orders
点击 “Authorize”,Scalar 弹出一个授权窗口,引导浏览器跳转到IdentityServer的授权端点
参数说明:
| 参数 | 说明 |
|---|---|
response_type=token |
表示使用隐式模式(直接要 access_token) |
client_id |
注册的客户端 ID(例如 orderingswaggerui) |
redirect_uri |
授权完成后的回调地址(必须与配置匹配) |
scope |
要申请访问的 API 权限(如 orders) |
state |
防止 CSRF 攻击的随机值 |

重新启动认证服务(Identity.API),设置Client ID和Scopes,然后点击Authorize,弹出IdentityServer进行登录

认证服务(Identity.API)不好调试流程,可以查看日志了解认证授权的流程:没有登录前,User is not authenticated(用户未认证)

登录成功后,跳转到授权页面,显示Showing consent: User has not yet consented(正在显示授权同意页面,因为这个用户还没有同意让这个客户端访问他的信息。)

授权完成后,这段日志的意思是:用户(13051f3a-c540-4f64-8048-b141d7a3e026)已授权客户端 orderingswaggerui 访问 orders 资源,并且记住了授权
-
SubjectId:当前登录用户的唯一标识(数据库里
AspNetUsers表的Id)。 -
ClientId:请求授权的客户端,即
orderingswaggerui(Swagger UI)。 -
RequestedScopes:客户端请求访问的资源范围,这里是
"orders"。 -
GrantedScopes:最终同意授权的范围(同上)。
-
ConsentRemembered = true:表示用户点击了“记住我的授权”,以后不会再弹出“同意授权”页面。
-
EventType = Information:普通信息事件。

这一段日志的含义:
-
客户端(Scalar)在用户同意后,
IdentityServer现在调用/connect/authorize/callback来处理授权回调。 也就是把用户授权结果重定向(redirect)回客户端。 -
IdentityServer需要加载用户的详细信息(例如 Email、用户名、状态等),所以它从数据库查出了这位用户的记录。 -
用户最终同意了访问
orders范围。

IdentityServer 已成功签发access_token给客户端 orderingswaggerui:
- GrantType:使用的授权模式是
implicit(隐式授权)。 - RedirectUri:授权成功后重定向到客户端(Swagger UI)的回调地址。
- Tokens:生成了一个访问令牌(access_token)。
- EventType = Success:代表令牌签发成功。

登录授权成功后,IdentityServer弹窗自动关闭,Scalar获取到token

流程说明
| 步骤 | Implicit Flow |
|---|---|
| 1 | 用户点击 Authorize |
| 2 | 跳转 IdentityServer 登录 |
| 3 | 如果未登录 → 输入用户名/密码 |
| 4 | 用户同意授权 |
| 5 | Scalar 获取 token |
| 6 | 使用 token 调用 API |
📌 创作不易,感谢支持!
每一篇内容都凝聚了心血与热情,如果我的内容对您有帮助,欢迎请我喝杯咖啡☕,您的支持是我持续分享的最大动力!
💬 加入交流群(QQ群):576434538
