Skip to content

流程总览 ​

一张图看完 ​

浏览器(SPA 5173 + React 登录页 /Account/Login)
   │
   │ ① 顶层导航 GET /connect/authorize?client_id=client-demo&redirect_uri=...&code_challenge=...
   ▼
AuthorizationController.Authorize ── 未认证? ──▶ TempData["IgnoreAuthenticationChallenge"]=true
   │                                              Challenge(RedirectUri=原请求)
   │                                              → 302 /Account/Login?ReturnUrl=<原请求>      ② 登录页
   │                                                                    │ 用户提交用户名/密码
   │                                                                    │ 表单 POST /Account/Login
   │                                                                    │ → SignInManager 种 cookie
   │                                                                    ▼ 顶层导航回 ReturnUrl
   ├─ 已认证 ──▶ 查永久授权(oi_ath)
   │                │ 无 + ConsentType=Explicit ▶ 302 /Account/Consent?...   ③ 同意页
   │                │                                          │ 点"同意"(POST submit.Accept)
   │                │                                          ▼
   │                │                              AuthorizationController.Accept
   │                │                              → 建永久授权 → SignIn → 签 code
   │                └─ 有 ▶ 直接 SignIn → 签 code
   ▼
302 redirect_uri?code=...&state=...
   │
   │ ④ 客户端 POST /connect/token(code + PKCE verifier)
   ▼
AuthorizationController.Exchange → 重建 claims → 签发 access/id(/refresh) token
   │
   │ (带 token 调 API:客户端 GET /weatherforecast + Authorization: Bearer → OpenIddict Validation 验签 → 200)
   │
   │ ⑤ 登出 GET /connect/logout → React 登出确认页 → POST /connect/logout → 清 cookie → 302 回客户端
   │
   │ ⑥(可选)外部登录:登录页点"使用 GitHub 登录" → GitHub → /callback/login/github → 落地或确认页 → 回到 ①

六个阶段的入口 ​

阶段页面核心代码关键状态
① 授权请求与未认证 Challenge① 授权请求AuthorizationController.Authorize + ConfigureApplicationCookieIdentity 应用 cookie 是否存在
② 登录② 登录Login.tsx + Controllers/AccountController.csIdentity 应用 cookie 被种下
③ 同意③ 同意AuthorizationController.Authorize 的 switch + Accept / Denyoi_ath 表里的永久授权
④ 换 token④ 换 tokenAuthorizationController.Exchangeoi_tok 表的授权码
⑤ 登出⑤ 登出AuthorizationController.Logout / LogoutPostcookie 被清、token 失效
⑥ 外部登录⑥ GitHub 外部登录AccountController(入口 / 落地 / 确认页端点)+ AuthenticationController + AddGitHub外部提供方凭据 + AspNetUserLogins 关联(未绑定须用户显式确认后建号)
载体内容谁写什么时候失效
.AspNetCore.Identity.Application(默认名)Identity 应用 cookie(用户会话,HttpOnly)SignInManager(登录端点 / 外部登录落地)票据 14 天滑动过期(默认值);登录时勾选"记住我" → 持久 cookie(带 expires),否则会话 cookie;登出时 SignOutAsync
.AspNetCore.Antiforgery.*防伪 cookieGET /Account/Antiforgery会话级
oi_app客户端注册启动时种子每次启动清空重建
oi_ath永久授权(= 用户已同意)AuthorizationController.Accept / 免同意分支每次启动清空 → 重启后重新弹同意页
oi_tok授权码 / refresh tokenOpenIddict 签发/撤销每次启动清空
oi_scoscope 资源映射启动时按需每次启动清空
AspNetUsers / AspNetRoles / AspNetUserLoginsIdentity 用户、角色、外部登录关联启动种子 / 外部登录落地端点不清(除非旧库被整体重建)

请求参数速查 ​

客户端在 ① 发来的参数,后面每一步都在用:

参数含义后续哪里用到
client_id谁在请求授权FindByClientIdAsync 查 oi_app
redirect_uri授权结果回到哪与注册值比对;签 code 后 302 到它
response_type=code要授权码OpenIddict 校验 + 客户端权限白名单
scope要哪些权限查永久授权按 scope 匹配;GetDestinations 决定 claim 去向
state客户端自己的防 CSRF 随机串OP 原样回传;由客户端校验
code_challenge / code_challenge_methodPKCE换 token 时校验 code_verifier
nonceid_token 防重放由客户端校验
promptlogin / consent / none②的重新登录判定、③的强制同意判定
max_age会话最长年龄① 的"cookie 是否够新鲜"判定

三个安全机制容易混

state 由客户端校验;防伪 token 与 PKCE 由 OP 校验——三者防的不是同一件事, 对照见安全机制对照(state / 防伪 / PKCE)。

OpenIddict + ASP.NET Core Identity 授权服务器,React 登录页,逐步拆解登录链路