[{"data":1,"prerenderedAt":41},["ShallowReactive",2],{"doc:\u002Fcontracts\u002Foauth\u002F07-logout":3},{"title":4,"route":5,"toc":6,"segments":36,"source":40},"07 — 登出与单点登出（RP-Initiated Logout）","\u002Fcontracts\u002Foauth\u002F07-logout",[7,10,13,16,19,23,26,29,32,34],{"id":8,"text":8,"depth":9},"背景与症状",2,{"id":11,"text":12,"depth":9},"根因-rp-登出-op-登出","根因：RP 登出 ≠ OP 登出",{"id":14,"text":15,"depth":9},"方案-rp-登出时顶层跳转到-op-登出入口-单点登出","方案：RP 登出时顶层跳转到 OP 登出入口（单点登出）",{"id":17,"text":18,"depth":9},"op-端点契约","OP 端点契约",{"id":20,"text":21,"depth":22},"1-登出入口-顶层导航-对称于-oauth-authorize","1. 登出入口（顶层导航，对称于 \u002Foauth\u002Fauthorize）",3,{"id":24,"text":25,"depth":22},"2-回跳白名单校验-op-登出页内部用","2. 回跳白名单校验（OP 登出页内部用）",{"id":27,"text":28,"depth":22},"3-prompt-login-强制重新登录-可选的-仅登出本站-语义","3. `prompt=login`（强制重新登录，可选的「仅登出本站」语义）",{"id":30,"text":31,"depth":9},"下游-rp-接入步骤","下游（RP）接入步骤",{"id":33,"text":33,"depth":9},"与既有端点的关系",{"id":35,"text":35,"depth":9},"安全",[37],{"type":38,"html":39},"html","\u003Ch1 id=\"07-登出与单点登出-rp-initiated-logout\" tabindex=\"-1\">07 — 登出与单点登出（RP-Initiated Logout）\u003C\u002Fh1>\n\u003Cp>返回 \u003Ca href=\"\u002Fcontracts\u002Foauth\">README\u003C\u002Fa>\u003C\u002Fp>\n\u003Cblockquote>\n\u003Cp>本节是\u003Cstrong>跨服务契约\u003C\u002Fstrong>：下游（kungal \u002F moyu \u002F wiki 等 RP）必须按此实现登出，否则会出现「登出后再点登录\u002F注册，直接静默登回刚才的账号」的回归。\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Ch2 id=\"背景与症状\" tabindex=\"-1\">背景与症状\u003C\u002Fh2>\n\u003Cp>集中式 SSO 下，\u003Ccode>oauth.kungal.com\u003C\u002Fcode> 是 OP（身份提供方），各站是 RP（接入方）。用户反馈：\u003Cstrong>在 wiki \u002F 补丁站登出后，点「登录」或「注册」会直接以刚才的账号登入，没有任何提示。\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Ch2 id=\"根因-rp-登出-op-登出\" tabindex=\"-1\">根因：RP 登出 ≠ OP 登出\u003C\u002Fh2>\n\u003Cp>OP 的「登录态」由两样东西决定，\u003Cstrong>都在 \u003Ccode>oauth.kungal.com\u003C\u002Fcode> 这个 origin 上\u003C\u002Fstrong>：\u003C\u002Fp>\n\u003Col>\n\u003Cli>OP 前端 \u003Ccode>localStorage\u003C\u002Fcode> 里持久化的 \u003Ccode>user\u003C\u002Fcode>（驱动 \u003Ccode>isLoggedIn\u003C\u002Fcode>）；\u003C\u002Fli>\n\u003Cli>\u003Ccode>refresh_token\u003C\u002Fcode> httpOnly cookie + DB \u003Ccode>sessions\u003C\u002Fcode> 行。\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cp>RP 登出只清掉了\u003Cstrong>那个站自己\u003C\u002Fstrong>的状态。而：\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Cstrong>\u003Ccode>localStorage\u003C\u002Fcode> 严格按 origin 隔离\u003C\u002Fstrong> —— 任何 RP 都无法清除 \u003Ccode>oauth.kungal.com\u003C\u002Fcode> 的 \u003Ccode>localStorage\u003C\u002Fcode>，OP 前端的 \u003Ccode>user\u003C\u002Fcode> 始终还在 → \u003Ccode>isLoggedIn\u003C\u002Fcode> 恒为真。\u003C\u002Fli>\n\u003Cli>跨站（如补丁站 \u003Ccode>touchgal.moe\u003C\u002Fcode> → \u003Ccode>oauth.kungal.com\u003C\u002Fcode>）的 \u003Ccode>SameSite=Lax\u003C\u002Fcode> refresh cookie 连后台 fetch 都带不过去 → cookie \u002F 会话也清不掉。\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>于是再点登录跳到 \u003Ccode>\u002Foauth\u002Fauthorize\u003C\u002Fcode> 时，OP 前端判定「已登录」+ 客户端 \u003Ccode>auto_consent=true\u003C\u002Fcode> → \u003Cstrong>静默发码\u003C\u002Fstrong> → 登回原账号。\u003C\u002Fp>\n\u003Cp>\u003Cstrong>关键结论：要清掉 OP 会话，浏览器必须顶层导航到 \u003Ccode>oauth.kungal.com\u003C\u002Fcode>\u003C\u002Fstrong> —— 只有真正访问到该 origin，才能同时清掉它的 cookie\u002F会话\u003Cstrong>和\u003C\u002Fstrong> \u003Ccode>localStorage\u003C\u002Fcode>。后台 fetch 两样都做不到。这正是 \u003Ca href=\"https:\u002F\u002Fopenid.net\u002Fspecs\u002Fopenid-connect-rpinitiated-1_0.html\">OpenID Connect RP-Initiated Logout\u003C\u002Fa> 解决的问题。\u003C\u002Fp>\n\u003Ch2 id=\"方案-rp-登出时顶层跳转到-op-登出入口-单点登出\" tabindex=\"-1\">方案：RP 登出时顶层跳转到 OP 登出入口（单点登出）\u003C\u002Fh2>\n\u003Cp>对同主人的一方生态，「登出 = 退出整个鲲 SSO」是最自然的语义。流程：\u003C\u002Fp>\n\u003Cpre class=\"shiki shiki-themes github-light github-dark\" style=\"background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8\" tabindex=\"0\">\u003Ccode class=\"language-text\">\u003Cspan class=\"line\">\u003Cspan>用户在 RP 点登出\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan>  → RP 清本地会话\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan>  → 浏览器顶层跳转 {OAUTH_API_BASE}\u002Foauth\u002Flogout?client_id=&#x3C;id>&#x26;redirect=&#x3C;回到RP的地址>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan>       → 后端 302 跳到 OP 前端登出页 \u002Fauth\u002Flogout（对称于 \u002Foauth\u002Fauthorize 跳同意页）\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan>       → OP 前端页清 refresh cookie + DB session + OP localStorage 的 user\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan>       → 校验 redirect 在白名单 → 跳回 RP\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan>  → 用户回到 RP（此时 OP 会话已清；再点登录会要求重新登录）\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"op-端点契约\" tabindex=\"-1\">OP 端点契约\u003C\u002Fh2>\n\u003Ch3 id=\"1-登出入口-顶层导航-对称于-oauth-authorize\" tabindex=\"-1\">1. 登出入口（顶层导航，对称于 \u002Foauth\u002Fauthorize）\u003C\u002Fh3>\n\u003Cpre class=\"shiki shiki-themes github-light github-dark\" style=\"background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8\" tabindex=\"0\">\u003Ccode class=\"language-text\">\u003Cspan class=\"line\">\u003Cspan>GET {OAUTH_API_BASE}\u002Foauth\u002Flogout?client_id=&#x3C;client_id>&#x26;redirect=&#x3C;post_logout_url>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan># 生产: https:\u002F\u002Foauth.kungal.com\u002Fapi\u002Fv1\u002Foauth\u002Flogout?client_id=...&#x26;redirect=...\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cul>\n\u003Cli>\u003Cstrong>RP 必须用 \u003Ccode>window.location.href\u003C\u002Fcode>（浏览器顶层导航）跳过来，不能用 fetch\u002FXHR\u003C\u002Fstrong> —— fetch 清不掉 OP 的 \u003Ccode>localStorage\u003C\u002Fcode>\u002Fcookie（见上文根因）。\u003C\u002Fli>\n\u003Cli>这是\u003Cstrong>后端入口\u003C\u002Fstrong>，会 302 跳到 OP 前端登出页 \u003Ccode>\u002Fauth\u002Flogout\u003C\u002Fcode>（与 \u003Ccode>\u002Foauth\u002Fauthorize\u003C\u002Fcode> 跳到前端同意页同一模式）。前端页执行：清 OP 会话（\u003Ccode>POST \u002Fapi\u002Fv1\u002Fauth\u002Flogout\u003C\u002Fcode> 删 session + 清 refresh cookie）+ 清 OP 前端 \u003Ccode>localStorage\u003C\u002Fcode> 的 \u003Ccode>user\u003C\u002Fcode> 与 \u003Ccode>access_token\u003C\u002Fcode> cookie → 校验 \u003Ccode>redirect\u003C\u002Fcode> → \u003Ccode>window.location\u003C\u002Fcode> 跳回。\u003C\u002Fli>\n\u003Cli>RP 复用访问 \u003Ccode>\u002Foauth\u002Fauthorize\u003C\u002Fcode> 时用的同一个 \u003Ccode>OAUTH_API_BASE\u003C\u002Fcode>（含 \u003Ccode>\u002Fapi\u002Fv1\u003C\u002Fcode>），无需额外配置 OP 前端域名；dev（前后端不同源）下也能正确解析（后端用 \u003Ccode>cfg.Server.FrontendURL\u003C\u002Fcode> 找前端页）。\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cdiv class=\"kun-table-wrap\">\u003Ctable>\u003Cthead>\n\u003Ctr>\n\u003Cth>参数\u003C\u002Fth>\n\u003Cth>必填\u003C\u002Fth>\n\u003Cth>说明\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>client_id\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>是\u003C\u002Ftd>\n\u003Ctd>发起登出的 RP 客户端 ID（用于校验 \u003Ccode>redirect\u003C\u002Fcode> 白名单）\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>redirect\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>否\u003C\u002Ftd>\n\u003Ctd>登出后回跳地址（post-logout redirect URI）。缺省 \u002F 校验不过 → 跳 OP 首页\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\u003C\u002Fdiv>\u003Ch3 id=\"2-回跳白名单校验-op-登出页内部用\" tabindex=\"-1\">2. 回跳白名单校验（OP 登出页内部用）\u003C\u002Fh3>\n\u003Cpre class=\"shiki shiki-themes github-light github-dark\" style=\"background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8\" tabindex=\"0\">\u003Ccode class=\"language-text\">\u003Cspan class=\"line\">\u003Cspan>GET \u002Fapi\u002Fv1\u002Foauth\u002Fpost-logout-redirect?client_id=&#x3C;id>&#x26;redirect=&#x3C;url>\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>无需鉴权。校验 \u003Ccode>redirect\u003C\u002Fcode> 的 \u003Cstrong>origin（scheme+host）是否匹配该 client 注册的任一 \u003Ccode>redirect_uri\u003C\u002Fcode> 的 origin\u003C\u002Fstrong>，匹配则回显，否则回空。\u003C\u002Fp>\n\u003Cp>\u003Cstrong>成功响应\u003C\u002Fstrong>：\u003C\u002Fp>\n\u003Cpre class=\"shiki shiki-themes github-light github-dark\" style=\"background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8\" tabindex=\"0\">\u003Ccode class=\"language-json\">\u003Cspan class=\"line\">\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">{ \u003C\u002Fspan>\u003Cspan style=\"color:#005CC5;--shiki-dark:#79B8FF\">\"code\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">: \u003C\u002Fspan>\u003Cspan style=\"color:#005CC5;--shiki-dark:#79B8FF\">0\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"color:#005CC5;--shiki-dark:#79B8FF\">\"data\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">: { \u003C\u002Fspan>\u003Cspan style=\"color:#005CC5;--shiki-dark:#79B8FF\">\"url\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">: \u003C\u002Fspan>\u003Cspan style=\"color:#032F62;--shiki-dark:#9ECBFF\">\"https:\u002F\u002Fwww.moyu.moe\u002F?logged_out=1\"\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\"> } }\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>\u003Ccode>data.url\u003C\u002Fcode> 为空字符串表示 \u003Ccode>redirect\u003C\u002Fcode> 不在白名单（防 open-redirect），调用方应回退到安全默认地址。\u003C\u002Fp>\n\u003Cblockquote>\n\u003Cp>白名单口径：复用 client 已注册的 \u003Ccode>redirect_uris\u003C\u002Fcode> 的 origin（一方生态下，能作回调目标的 origin 即可信作登出回跳目标）。如需更严格，后续可加独立的 \u003Ccode>post_logout_redirect_uris\u003C\u002Fcode> 注册项。\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Ch3 id=\"3-prompt-login-强制重新登录-可选的-仅登出本站-语义\" tabindex=\"-1\">3. \u003Ccode>prompt=login\u003C\u002Fcode>（强制重新登录，可选的「仅登出本站」语义）\u003C\u002Fh3>\n\u003Cp>\u003Ccode>GET \u002Foauth\u002Fauthorize\u003C\u002Fcode> 新增可选查询参数 \u003Ccode>prompt\u003C\u002Fcode>：\u003C\u002Fp>\n\u003Cdiv class=\"kun-table-wrap\">\u003Ctable>\u003Cthead>\n\u003Ctr>\n\u003Cth>值\u003C\u002Fth>\n\u003Cth>行为\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>login\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>即使 OP 仍有会话，也\u003Cstrong>强制显示登录界面\u003C\u002Fstrong>（不走 auto-consent 静默放行）\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>（空）\u003C\u002Ftd>\n\u003Ctd>默认行为（有会话 + auto_consent → 静默发码）\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\u003C\u002Fdiv>\u003Cp>适用「只想登出本站、但本站再登要重新确认」的 RP：登出时\u003Cstrong>不\u003C\u002Fstrong>做全局单点登出，而是在下次发起 authorize 时带上 \u003Ccode>prompt=login\u003C\u002Fcode>。与方案 1（单点登出）二选一即可。\u003C\u002Fp>\n\u003Ch2 id=\"下游-rp-接入步骤\" tabindex=\"-1\">下游（RP）接入步骤\u003C\u002Fh2>\n\u003Cp>\u003Cstrong>单点登出（推荐）\u003C\u002Fstrong>——把登出按钮改成顶层跳转：\u003C\u002Fp>\n\u003Cpre class=\"shiki shiki-themes github-light github-dark\" style=\"background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8\" tabindex=\"0\">\u003Ccode class=\"language-ts\">\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D;--shiki-dark:#6A737D\">\u002F\u002F RP 登出处理\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49;--shiki-dark:#F97583\">const\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1;--shiki-dark:#B392F0\"> logout\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49;--shiki-dark:#F97583\"> =\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49;--shiki-dark:#F97583\"> async\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\"> () \u003C\u002Fspan>\u003Cspan style=\"color:#D73A49;--shiki-dark:#F97583\">=>\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D;--shiki-dark:#6A737D\">  \u002F\u002F 1. 清本站自己的会话（清 token \u002F 本地 store \u002F 调用本站后端登出）\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49;--shiki-dark:#F97583\">  await\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1;--shiki-dark:#B392F0\"> clearLocalSession\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">()\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D;--shiki-dark:#6A737D\">  \u002F\u002F 2. 顶层跳转到 OP 登出入口，登出后回到本站。\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D;--shiki-dark:#6A737D\">  \u002F\u002F    OAUTH_API_BASE = 你访问 \u002Foauth\u002Fauthorize 用的同一个 base（含 \u002Fapi\u002Fv1）。\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#D73A49;--shiki-dark:#F97583\">  const\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5;--shiki-dark:#79B8FF\"> back\u003C\u002Fspan>\u003Cspan style=\"color:#D73A49;--shiki-dark:#F97583\"> =\u003C\u002Fspan>\u003Cspan style=\"color:#6F42C1;--shiki-dark:#B392F0\"> encodeURIComponent\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">(window.location.origin \u003C\u002Fspan>\u003Cspan style=\"color:#D73A49;--shiki-dark:#F97583\">+\u003C\u002Fspan>\u003Cspan style=\"color:#032F62;--shiki-dark:#9ECBFF\"> '\u002F'\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">  window.location.href \u003C\u002Fspan>\u003Cspan style=\"color:#D73A49;--shiki-dark:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"color:#032F62;--shiki-dark:#9ECBFF\"> `${\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5;--shiki-dark:#79B8FF\">OAUTH_API_BASE\u003C\u002Fspan>\u003Cspan style=\"color:#032F62;--shiki-dark:#9ECBFF\">}\u002Foauth\u002Flogout?client_id=${\u003C\u002Fspan>\u003Cspan style=\"color:#005CC5;--shiki-dark:#79B8FF\">MY_CLIENT_ID\u003C\u002Fspan>\u003Cspan style=\"color:#032F62;--shiki-dark:#9ECBFF\">}&#x26;redirect=${\u003C\u002Fspan>\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">back\u003C\u002Fspan>\u003Cspan style=\"color:#032F62;--shiki-dark:#9ECBFF\">}`\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#24292E;--shiki-dark:#E1E4E8\">}\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>\u003Cstrong>注册要求\u003C\u002Fstrong>：回跳地址（\u003Ccode>redirect\u003C\u002Fcode>）的 origin 必须与该 client 注册的某个 \u003Ccode>redirect_uri\u003C\u002Fcode> 同源。例如 \u003Ccode>redirect_uri = https:\u002F\u002Fwww.moyu.moe\u002Fauth\u002Fcallback\u003C\u002Fcode>，则 \u003Ccode>redirect = https:\u002F\u002Fwww.moyu.moe\u002F...\u003C\u002Fcode> 合法。\u003C\u002Fp>\n\u003Cblockquote>\n\u003Cp>注意：不要只在前端「清得更干净」就完事 —— \u003Ccode>localStorage\u003C\u002Fcode> 跨 origin 清不掉 OP 的，必须顶层跳转到 OP 登出入口。\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Ch2 id=\"与既有端点的关系\" tabindex=\"-1\">与既有端点的关系\u003C\u002Fh2>\n\u003Cdiv class=\"kun-table-wrap\">\u003Ctable>\u003Cthead>\n\u003Ctr>\n\u003Cth>端点\u003C\u002Fth>\n\u003Cth>作用\u003C\u002Fth>\n\u003Cth>与本节关系\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>POST \u002Fapi\u002Fv1\u002Fauth\u002Flogout\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>删当前 session + 清 refresh cookie（需 Bearer）\u003C\u002Ftd>\n\u003Ctd>OP 登出页内部调用它清后端会话\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>POST \u002Fapi\u002Fv1\u002Foauth\u002Frevoke\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>RFC 7009 吊销指定 token\u003C\u002Ftd>\n\u003Ctd>S2S 吊销；不清浏览器 OP 前端状态，\u003Cstrong>不能\u003C\u002Fstrong>替代登出入口\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>GET \u002Fapi\u002Fv1\u002Foauth\u002Flogout\u003C\u002Fcode>（后端入口）\u003C\u002Ftd>\n\u003Ctd>\u003Cstrong>本节新增\u003C\u002Fstrong>：302 跳到 OP 前端登出页\u003C\u002Ftd>\n\u003Ctd>RP 登出的正确入口（顶层导航）\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>GET \u002Fauth\u002Flogout\u003C\u002Fcode>（OP 前端页）\u003C\u002Ftd>\n\u003Ctd>\u003Cstrong>本节新增\u003C\u002Fstrong>：清 OP 会话 + 校验回跳\u003C\u002Ftd>\n\u003Ctd>由上面的入口 302 进来；RP 一般不直接跳这个\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\u003C\u002Fdiv>\u003Ch2 id=\"安全\" tabindex=\"-1\">安全\u003C\u002Fh2>\n\u003Cul>\n\u003Cli>\u003Cstrong>Open-redirect 防护\u003C\u002Fstrong>：\u003Ccode>redirect\u003C\u002Fcode> 必须通过白名单校验（origin 匹配注册的 \u003Ccode>redirect_uri\u003C\u002Fcode>），否则回退安全默认地址。\u003C\u002Fli>\n\u003Cli>登出入口对未登录访问也安全（无会话可清时直接按白名单回跳 \u002F 跳首页）。\u003C\u002Fli>\n\u003Cli>顶层导航不依赖跨站 cookie，补丁站（跨主域）同样可靠。\u003C\u002Fli>\n\u003C\u002Ful>\n","kun-galgame-infra\u002Fdocs\u002Fintegration\u002Foauth\u002F07-logout.md",1781708342151]