React - 账号密码登录

This commit is contained in:
柳清爽
2025-03-29 17:02:40 +08:00
parent 7e7c199996
commit 870cec6978
4 changed files with 325 additions and 150 deletions

View File

@@ -2,19 +2,51 @@
import { createContext, useContext, useEffect, useState, type ReactNode } from "react"
import { useRouter } from "next/navigation"
import { validateToken } from "@/lib/api"
// 安全的localStorage访问方法
const safeLocalStorage = {
getItem: (key: string): string | null => {
if (typeof window !== 'undefined') {
return localStorage.getItem(key)
}
return null
},
setItem: (key: string, value: string): void => {
if (typeof window !== 'undefined') {
localStorage.setItem(key, value)
}
},
removeItem: (key: string): void => {
if (typeof window !== 'undefined') {
localStorage.removeItem(key)
}
}
}
interface User {
id: number;
username: string;
account?: string;
avatar?: string;
}
interface AuthContextType {
isAuthenticated: boolean
token: string | null
login: (token: string) => void
user: User | null
login: (token: string, userData: User) => void
logout: () => void
updateToken: (newToken: string) => void
}
const AuthContext = createContext<AuthContextType>({
isAuthenticated: false,
token: null,
user: null,
login: () => {},
logout: () => {},
updateToken: () => {}
})
export const useAuth = () => useContext(AuthContext)
@@ -25,43 +57,82 @@ interface AuthProviderProps {
export function AuthProvider({ children }: AuthProviderProps) {
const [token, setToken] = useState<string | null>(null)
const [user, setUser] = useState<User | null>(null)
const [isAuthenticated, setIsAuthenticated] = useState(false)
const [isLoading, setIsLoading] = useState(true)
const router = useRouter()
// 检查token有效性并初始化认证状态
useEffect(() => {
// 客户端检查token
if (typeof window !== "undefined") {
const storedToken = localStorage.getItem("token")
const initAuth = async () => {
setIsLoading(true)
const storedToken = safeLocalStorage.getItem("token")
if (storedToken) {
setToken(storedToken)
setIsAuthenticated(true)
} else {
setIsAuthenticated(false)
// 暂时禁用重定向逻辑,允许访问所有页面
// 将来需要恢复登录验证时,取消下面注释
/*
if (pathname !== "/login") {
router.push("/login")
try {
// 验证token是否有效
const isValid = await validateToken()
if (isValid) {
// 从localStorage获取用户信息
const userDataStr = safeLocalStorage.getItem("user")
if (userDataStr) {
const userData = JSON.parse(userDataStr) as User
setToken(storedToken)
setUser(userData)
setIsAuthenticated(true)
} else {
// token有效但没有用户信息清除token
handleLogout()
}
} else {
// token无效清除
handleLogout()
}
} catch (error) {
console.error("验证token时出错:", error)
handleLogout()
}
*/
}
setIsLoading(false)
}
initAuth()
}, [])
const login = (newToken: string) => {
localStorage.setItem("token", newToken)
const handleLogout = () => {
safeLocalStorage.removeItem("token")
safeLocalStorage.removeItem("user")
setToken(null)
setUser(null)
setIsAuthenticated(false)
}
const login = (newToken: string, userData: User) => {
safeLocalStorage.setItem("token", newToken)
safeLocalStorage.setItem("user", JSON.stringify(userData))
setToken(newToken)
setUser(userData)
setIsAuthenticated(true)
}
const logout = () => {
localStorage.removeItem("token")
setToken(null)
setIsAuthenticated(false)
handleLogout()
// 登出后不强制跳转到登录页
// router.push("/login")
}
return <AuthContext.Provider value={{ isAuthenticated, token, login, logout }}>{children}</AuthContext.Provider>
// 用于刷新 token 的方法
const updateToken = (newToken: string) => {
safeLocalStorage.setItem("token", newToken)
setToken(newToken)
}
return (
<AuthContext.Provider value={{ isAuthenticated, token, user, login, logout, updateToken }}>
{isLoading ? <div className="flex h-screen w-screen items-center justify-center">...</div> : children}
</AuthContext.Provider>
)
}