IdentityServer4认证授权之授权码模式(Authorization Code+PKCE)

news/2025/12/4 2:38:59/文章来源:https://www.cnblogs.com/pengboke/p/19304589

前言

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 的,而不是其他服务。验证签发tokenaud
  • 签发者(Issuers):确保Token是由受信任的认证中心签发。验证签发tokeniss

image-20251104012258084

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

image-20251104014215886

然后我们启动认证服务,在..\eShop\src\Identity.API目录下运行以下命令:

dotnet run --urls https://localhost:5243/

image-20251103193457394

2.配置授权码模式(Authorization Code + PKCE)

隐式模式(Implicit)已经被淘汰了,eShop 官方示例用 Implicit,是为了演示方便(快速看到授权效果),让 Swagger UI(或浏览器)/Scalar能够直接拿到 Access Token,方便开发和测试。

在 OAuth 2.1 规范中(2023 年正式发布),Implicit 模式已被标记为弃用

  • Access Token 暴露在 URL;
  • 无法安全刷新;
  • 浏览器中易被脚本窃取;
  • 无法防止中间人攻击。

所以现代标准中 强制推荐改用 Authorization Code + PKCE

既然学习,我们也看看授权码模式(Authorization Code + PKCE),我们就以购物车服务(Basket.API)为例,因为购物车的Scalar也是我们为了学习加上的,购物车服务(Basket.API)因为使用了Grpc,所以只能使用https协议,我们把接口也加上了api版本

image-20251104235344290

先添加以下配置:

 // 授权类型:Authorization Code + PKCEAllowedGrantTypes = GrantTypes.Code,// SPA/Scalar 客户端不保存 secret,所以不要求 client_secretRequireClientSecret = false,// 强制使用 PKCE(安全性必须)RequirePkce = true,// 是否显示用户同意授权页面RequireConsent = true, // 强制每次授权确认// token 生命周期和刷新控制(可选)AllowOfflineAccess = false, // 如果暂时不需要 refresh token// 允许跨域请求的 originAllowedCorsOrigins ={"https://localhost:5221"  // Scalar / Swagger UI 所在的域名},

为什么授权码模式(Authorization Code + PKCE)会触发跨域?隐式模式(Implicit )不需要(这是我调试过程遇到的问题,我提前记录一下)

Implicit 流 下:

  • 浏览器通过 302 重定向 + URL fragment 获取 token
  • 不走 JS Ajax,所以不会触发 CORS

Authorization Code + PKCE 下:

  • 前端 SPA 需要用 JS 通过 POST /connect/token 来交换 code → access_token
  • 浏览器 JS 发起的是跨域 AJAX 请求
  • IdentityServer 如果没有允许该 Origin,就报 CorsPolicyService did not allow origin: ...

image-20251105000220581

然后配置回调地址(RedirectUris)和允许访问的的API范围(AllowedScopes)

为什么需要配置 RedirectUris

  • OAuth2 / OIDC 协议要求每个客户端注册 回调地址(redirect_uri)。

  • 当用户在 IdentityServer 授权成功后,浏览器会重定向到这个地址,并带上 code 或 token

  • 严格匹配:IdentityServer 会检查请求中的 redirect_uri 是否在客户端注册列表里,否则会报:Invalid redirect_uri

为什么还要配置 openid / profile scopes?

这些 scope 来自 OpenID Connect (OIDC) 协议:

  • openid → 表示这是一个 OIDC 请求(IdentityServer 会返回 id_token)
  • profile → 请求用户信息(如名字、头像等)

区别于普通 API scope

  • API scope(比如 basket)只控制访问后端 API
  • openid/profile 用于获取用户身份信息(JWT 中的 claims)

如果你的前端只需要访问 API,不关心用户信息,可以不用 openid/profileopenid/profile 可以根据需要决定是否保留。

image-20251105000716645

定义一个名为 "basket" 的受保护 API,并指定访问它需要 "basket" 这个 scope。

image-20251105001310689

OAuth2新增授权码模式(Authorization Code + PKCE )

image-20251105001538818

RequireAuthorization给这个 API 分组下的所有端点应用授权策略,也就是需要用户已经登录或具备某些权限才能访问这些接口。

var api = vApi.MapGroup("api/Basket").HasApiVersion(1, 0).HasApiVersion(2, 0).RequireAuthorization();

image-20251105003204676

如果配置RequireAuthorization()没有token访问接口返回401(无权限)

image-20251105003342117

所有代码配置完成后,启动购物车服务(Basket.API),打开Scalar,选择OAuth2,发现多了一种授权方案(Authorization Code)

跟之前一样配置:Client IDUse PKCEScopes

Client Secret 可选

  • 对于 SPA 或前端客户端(比如 Scalar 文档 UI、Swagger UI),不存储密钥是推荐做法,因为前端代码无法安全保管 secret。

  • 所以在IdentityServer中,你可以配置 RequireClientSecret = false

  • 如果你在 Scalar 上看到 Client Secret: XYZ123,那只是生成的示例,并不是必须的。

PKCE 强制使用 SHA-256

  • PKCE(Proof Key for Code Exchange)是 Authorization Code 流的增强安全机制,用于前端应用防止授权码被截获。
  • PKCE 流程里有一个 code_challenge,必须经过 SHA-256 哈希(S256)生成,原始的 plain 方法被现代安全标准弃用。
  • 因此 IdentityServer 会要求 code_challenge_method = S256,不能用 plain,否则报错:code_challenge_method of plain is not allowed

image-20251105001926111

输入用户名和密码,然后点击登录

image-20251105002848800

再点击Yes,Allow(允许授权)

image-20251105002929930

打开/api/Basket/{customerId},测试一下,查询正常

image-20251105003038439

3.授权码模式流程(Authorization Code + PKCE)

在查看 OpenAPI 规范文档时,我们为 oauth2 安全方案配置了两种授权模式:ImplicitAuthorization Code,分别对应浏览器直接获取 token 和通过授权码交换 token 的安全流程,并指定了 basket API 的访问范围。

https://localhost:5221/openapi/v1.json

image-20251105004034522

先关闭认证服务(Identity.API),然后设置Client IDUse PKCEScopes,点击Authorize

查看Scalar发起的授权请求:

  • response_type=code:授权码模式。
  • scope:请求访问的范围。
  • code_challenge & code_challenge_method:PKCE,客户端生成随机字符串和散列,服务器用来校验。
  • redirect_uri:授权成功后回调地址。
  • state:防 CSRF,同时保持请求上下文
  • client_id:当前客户端的唯一标识
# 原请求
https://localhost:5243/connect/authorize?response_type=code&code_challenge=3_V716AyAbS7uKOkhK6jDTW7Ho8As2_zq6EOBA_i7jQ&code_challenge_method=S256&redirect_uri=https%3A%2F%2Flocalhost%3A5221%2Fscalar%2Fv1&client_id=basketswaggerui&state=78jzgb2i&scope=basket
# 解码后 redirect_uri加密了
https://localhost:5243/connect/authorize?
response_type=code&
code_challenge=3_V716AyAbS7uKOkhK6jDTW7Ho8As2_zq6EOBA_i7jQ&
code_challenge_method=S256&
redirect_uri=https://localhost:5221/scalar/v1&
client_id=basketswaggerui&
state=78jzgb2i&
scope=basket

image-20251105004502293

启动认证服务(Identity.API)和购物车服务(Basket.API),设置Client IDUse PKCEScopes,点击Authorize

没登录前:Showing login: User is not authenticated(显示登录页,用户没有认证)

image-20251105005336634

登陆成功后:Showing consent: User has not yet consented(显示授权:用户未授权)

image-20251105005723209

登录&授权后:Scalar发送 POST 请求到 Token 端点

  • client_id:客户端唯一标识
  • redirect_uri:回调地址,必须匹配注册信息
  • code:授权码,用于换取 Access Token
  • grant_type:授权模式,这里是授权码模式(authorization_code)
  • code_verifier:PKCE 验证码,保证授权码安全
POST https://localhost:5243/connect/token
client_id=basketswaggerui&
redirect_uri=https%3A%2F%2Flocalhost%3A5221%2Fscalar%2Fv1&
code=32BAD9BF9537F37C142CAC44066BFC80F5A81DDBB61B74E06445FA61881D0A85-1&
grant_type=authorization_code&
code_verifier=5JddRWZjBe72ixVPwZMxIQblPyhe_MivmcNUQFa2LEI

为什么授权码模式(Authorization Code + PKCE)会触发跨域?隐式模式(Implicit )不需要(这是我调试过程遇到的问题,我提前记录一下)

上面记录了这个问题,就是因为Scalar客户端发起了Ajax请求获取token,所以认证服务(Identity.API)需要配置AllowedCorsOrigins

image-20251105005842494Scalar设置Access Token,所有api调用就可以使用这个Access Token

image-20251105010600233

SPA/Scalar 通常不使用 Refresh Token,是因为浏览器无法安全存储长期凭证,短期 Access Token + PKCE 重新授权比使用 Refresh Token 更安全。

image-20251105010745695

流程说明

步骤 Authorization Code + PKCE Flow
1 用户点击 Authorize
2 跳转 IdentityServer 登录
3 如果未登录 → 输入用户名/密码
4 用户同意授权
5 IdentityServer 重定向回客户端(带 授权码 code
6 客户端使用 code + code_verifier 向 IdentityServer Token Endpoint 交换 Access Token
7 IdentityServer 返回 Access Token(可选 ID Token)
8 客户端使用 Access Token 调用受保护 API

📌 创作不易,感谢支持!

每一篇内容都凝聚了心血与热情,如果我的内容对您有帮助,欢迎请我喝杯咖啡☕,您的支持是我持续分享的最大动力!

💬 加入交流群(QQ群):576434538

微信打赏

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/986209.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

IdentityServer4认证授权之OpenId Connect认证流程

前言 1.认证服务日志中间件(RequestLoggingMiddleware) 经过之前的学习,项目基本都能跑起来了(除了HybridApp),但是我还是想有始有终,全部学完,如果你此时还运行不了项目,先看看我的验证过程即可 为了了解认证服…

IdentityServer4认证授权之OpenId Connect方案

前言 1.授权(AddAuthorization) WebhookClient是基于Blazor开发的Web项目,即像客户端,又像服务端,所以认证授权和之前纯后端服务有些不一样,还是一行一行学习吧 这里没有添加授权方案,默认的授权方案是认证登录之…

IdentityServer4认证授权之隐式流模式(Implicit)

前言 1.配置服务认证授权 订单服务(Ordering.API)配置了认证授权,所以我们使用Scalar调试接口的时候也需要认证服务(Identity.API)颁发的token,上面的测试就是401无权限 首先我们再回忆下我们认证授权配置了那些:认…

.NET Core 微服务之RabbitMQ分布式链路追踪

前言 1.分布式追踪 分布式追踪是一种用来观察、分析分布式系统中一次请求在多个服务之间调用路径的技术。 分布式追踪的核心概念 Trace(跟踪/链路) Trace = 一次业务请求的完整链路。 例如:用户下单从开始到结束的完…

Asp.Net Core 过滤器之Filter

过滤器(Filter) 1.概念 过滤器(Filter)是 ASP.NET Core MVC 的一种 拦截器机制,可以在 Controller 或 Action 执行前后插入逻辑。 它类似中间件,但只作用于 MVC/Web API 请求(控制器和操作方法),不能拦截静态文…

Asp.Net Core 请求管道中间件之Middleware

前言 中间件(Middleware) 概念 中间件是 ASP.NET Core 请求处理管道(pipeline) 中的一段可插拔组件,接收 HttpContext、执行任意逻辑、并决定是否把请求交给管道中的下一个中间件。管道呈“洋葱模型”(请求顺序进入…

Git推送从失败到成功的解决方案

问题描述 今天在尝试将本地代码推送到GitHub远程仓库时,遇到了推送失败的问题。使用git push命令后,出现了以下错误: fatal: unable to access https://github.com/guchen66/IT.Tangdao.Core.git/: OpenSSL SSL_rea…

Microsoft-Store-error

Microsoft-Store-error导航 (返回顶部)1. Store初始化失败1.1 为何要卸载Edge 1.2 如何卸载Edge 1.3 为何删除Edge会影响微软商店2. 微软商店无法联网2.1 解除网络隔离的办法有:3. CheckNetIsolation解除网络隔离3.1 查…

STM32 HAL库 硬件IIC 从机一些问题整理(转载)

一、从机双地址,在回调函数中获取主机访问的地址:void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *I2cHandle) {uint16_t slaveaddrcode = I2C_GET_ADDR_MATCH(I2cHandle);printf("R:%d\r\n",sl…

本地人推荐的火锅,天台火锅/麻辣火锅/老火锅/市井火锅/川渝火锅约会地点推荐榜单

专业视角下的川渝火锅团建选址指南 随着企业团建需求的多元化发展,川渝火锅凭借其独特的社交属性与浓郁的文化氛围,已成为企业团建活动的优选场所。本文基于市场调研数据与消费者反馈,从空间容量、服务质量、特色体…

OBDSTAR P003+ Kit for DC706 Tablets: Simplify ECU, EEPROM, Flash IMMO Data Diagnostics Programming

Troubleshooting ECU & IMMO Challenges on European/American Cars? Meet the OBDSTAR P003+ Kit The Pain Point: Decrypting ECU & IMMO Data on European/American Vehicles For European and American m…

全程复盘:一次枚举值永远 Cloud2的坑——从玄学随机到只读属性

问题描述 在 .NET 6 + WPF 程序中,使用 TangdaoDataFaker<MusicInfo>.Build(200000) 生成测试数据时,控制台 20 条并行日志显示 QQ / Cloud / Kugou 随机分布,但 DataGrid 界面整屏只显示 Cloud2。同一套代码…

M726芯片

根据您提供的《M726 数据手册》,我为您整理了该芯片的关键性能参数,并列出了性能相近的竞品型号及价格参考(基于公开市场信息,实际价格以供应商报价为准):M726 芯片核心性能摘要 类别 参数内核 ARM Cortex-M0,最…

Fast Easy Electric Oil Siphon Pump: Professional Fluid Transfer for Cars, Motorcycles Boats

The Hidden Challenges of Fluid Transfer: Why Mechanics and Car Owners Need a Better Solution Anyone who’s ever drained engine oil, changed coolant, or refilled a motorcycle’s fuel tank knows the frus…

AutoCloseable接口 try-with-resources 、 try-catch-finally

在学习过程中发现了这样一段注释/*** 实现了 AutoCloseable 接⼝的类,在 try() ⾥声明该类实例的时候,在 try 结束后⾃动调⽤的 close ⽅法,这个动作会早于* finally ⾥调⽤的⽅法,不管是否出现异常,try() ⾥的实…

第44天(中等题 数据结构)

打卡第四十四天 2道中等题题目:思路:以每个点为中心,统计与它距离相同的点对数量 代码: class Solution { public:int numberOfBoomerangs(vector<vector<int>>& points) {int ans = 0;int n = po…

rizhi

rizhicat /tmp/ray/session_latest/logs/dashboard_agent.log

element-plus el-select

<template><div class="app"><h4>=========默认情况下的select组件在设置collapse-tags-tooltip后,只有在鼠标移入折叠标签后才显示文本</h4><el-selectmultiplecollapse-tagsc…

centos6.9编译安装python37——SSL 模块缺失、GCOV 链接错误,以及 Bash 命令缓存混乱

安装参考这篇 https://www.cnblogs.com/opsprobe/p/11266939.html 🚀 Python 编译与环境部署深度指南:告别 SSL 缺失和 Bash 缓存困扰 📝 导言 在 Linux 系统上从源码编译安装 Python,尤其是在企业级环境(如 Ce…

在 Windows 上本地部署 ComfyUI + zImage Turbo 模型(低显存友好)

原文:https://www.cnblogs.com/zwj/p/19304354/ai_local_zimg我是觉得我原文写的可能比较乱,于是让AI整理了一下我的原文,下方内容就是QwenMax根据我原文的内容生成的,仅供参考。 在 Windows 上本地部署 ComfyUI +…