Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | import { UserManager, WebStorageStateStore } from 'oidc-client-ts'
/**
* 内存存储:登录后的 User(含 access_token)只存于此,不写入 localStorage/sessionStorage。
* 刷新页面或关闭标签即丢失,符合 D8「access_token 仅存内存」。
* 实现标准 Web Storage 接口(含 length/key/clear),以满足 oidc-client-ts v3 的存储类型。
*/
class MemoryStore implements Storage {
private readonly map = new Map<string, string>()
get length(): number {
return this.map.size
}
getItem(key: string): string | null {
return this.map.has(key) ? this.map.get(key)! : null
}
setItem(key: string, value: string): void {
this.map.set(key, value)
}
removeItem(key: string): void {
this.map.delete(key)
}
clear(): void {
this.map.clear()
}
key(index: number): string | null {
return Array.from(this.map.keys())[index] ?? null
}
}
const authority = import.meta.env.VITE_OIDC_AUTHORITY ?? 'https://auth.anjibao.cn'
const clientId = import.meta.env.VITE_OIDC_CLIENT_ID ?? '6db48077896a73e99c4a'
const scope = import.meta.env.VITE_OIDC_SCOPE ?? 'openid profile phone'
export const userManager = new UserManager({
authority,
client_id: clientId,
redirect_uri: `${window.location.origin}/auth/callback`,
post_logout_redirect_uri: `${window.location.origin}/logged-out`,
response_type: 'code',
scope,
// 授权码流程跨页面跳转所需的临时 state(code_verifier/nonce),同标签页内保留
stateStore: new WebStorageStateStore({ store: window.sessionStorage }),
// 登录态(含 token)仅内存
userStore: new WebStorageStateStore({ store: new MemoryStore() }),
// 第一版不开隐藏 iframe 自动续期:过期/失效由 401 触发一次重新授权(同站 SSO 会话在则无感跳回)
automaticSilentRenew: false,
// 令牌足以解身份,无需额外再拉 userinfo
loadUserInfo: false
})
/** 发起登录(整页跳到 IdP;在 iframe 内即 iframe 内跳转)。 */
export function signinRedirect(returnPath?: string): Promise<void> {
return userManager.signinRedirect({ state: { returnPath } })
}
/** 处理授权码回调,交换并装载登录态,返回发起登录前的路径。 */
export async function handleRedirectCallback(): Promise<string> {
const user = await userManager.signinRedirectCallback()
return (user.state as { returnPath?: string } | undefined)?.returnPath ?? '/'
}
/**
* 登出:走 OIDC RP-Initiated Logout,跳转 IdP 结束 SSO 会话后回到 /logged-out。
* 转介人在 Casdoor 仅消费本应用,结束全局会话无「连带退出其他系统」副作用。
*/
export function signoutRedirect(): Promise<void> {
return userManager.signoutRedirect()
}
|