PersonalWebApplication/Client/src/hooks/useAuth.ts
cc 9685336903 feat(client): photos API client + expose auth token
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 21:18:43 +08:00

80 lines
2.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useCallback, useState } from 'react'
import { login as loginRequest } from '../api/auth'
// storage 键:登录态写在浏览器。
// - 勾“记住我” → localStorage关浏览器再开仍登录
// - 不勾 → sessionStorage刷新仍在关标签页/浏览器即清)
const STORAGE_KEY = 'ip.auth'
interface Session {
username: string
token: string
}
function parseSession(raw: string | null): Session | null {
if (!raw) return null
try {
const parsed = JSON.parse(raw) as Partial<Session>
if (typeof parsed.username === 'string' && typeof parsed.token === 'string') {
return { username: parsed.username, token: parsed.token }
}
} catch {
// 解析失败(被手动改坏等)当作未登录
}
return null
}
// 先读 localStorage记住我再读 sessionStorage仅本次会话
function loadSession(): Session | null {
return (
parseSession(localStorage.getItem(STORAGE_KEY)) ??
parseSession(sessionStorage.getItem(STORAGE_KEY))
)
}
export interface Auth {
/** 已登录则为当前用户名,否则为 null */
username: string | null
/** 当前会话 tokenJWT未登录为 null。用于受保护接口的 Authorization 头 */
token: string | null
/** 校验凭据remember 为 true 时持久化到 localStorage否则只存 sessionStorage */
signIn: (username: string, password: string, remember: boolean) => Promise<void>
/** 退出登录并清除浏览器里的会话(两种 storage 都清) */
signOut: () => void
}
/**
* 登录态管理。初始值从 localStorage / sessionStorage 恢复,
* 因此刷新页面后仍停留在登录后界面(“记住我”决定关浏览器后是否还在)。
*/
export function useAuth(): Auth {
const [session, setSession] = useState<Session | null>(loadSession)
const signIn = useCallback(
async (username: string, password: string, remember: boolean) => {
const result = await loginRequest(username, password)
const next: Session = { username: result.username, token: result.token }
setSession(next)
const raw = JSON.stringify(next)
if (remember) {
// 记住我:持久化,关浏览器再开仍登录。
localStorage.setItem(STORAGE_KEY, raw)
sessionStorage.removeItem(STORAGE_KEY)
} else {
// 不记住:仅本次会话,刷新仍在、关标签页/浏览器即清。
sessionStorage.setItem(STORAGE_KEY, raw)
localStorage.removeItem(STORAGE_KEY)
}
},
[],
)
const signOut = useCallback(() => {
setSession(null)
localStorage.removeItem(STORAGE_KEY)
sessionStorage.removeItem(STORAGE_KEY)
}, [])
return { username: session?.username ?? null, token: session?.token ?? null, signIn, signOut }
}