feat: refresh token

This commit is contained in:
naiba
2024-11-05 00:02:43 +08:00
parent b1a0b607da
commit bfdae2838f
5 changed files with 35 additions and 20 deletions

View File

@@ -5,6 +5,10 @@ export const getProfile = async (): Promise<User> => {
return fetcher<User>(FetcherMethod.GET, '/api/v1/profile', null)
}
export const refreshToken = async (): Promise<any> => {
return fetcher<any>(FetcherMethod.GET, '/api/v1/refresh_token', null)
}
export const login = async (username: string, password: string): Promise<any> => {
return fetcher<any>(FetcherMethod.POST, '/api/v1/login', { username, password })
}

View File

@@ -1,8 +1,8 @@
import { createContext, useContext, useEffect, useMemo, useState } from "react";
import { createContext, useContext, useEffect, useMemo, useRef } from "react";
import { useNavigate } from "react-router-dom";
import { useMainStore } from "./useMainStore";
import { AuthContextProps } from "@/types";
import { getProfile, login as loginRequest } from "@/api/user";
import { getProfile, login as loginRequest, refreshToken } from "@/api/user";
import { toast } from "sonner";
const AuthContext = createContext<AuthContextProps>({
@@ -16,23 +16,34 @@ export const AuthProvider = ({ children }: {
}) => {
const profile = useMainStore(store => store.profile)
const setProfile = useMainStore(store => store.setProfile)
const [lastUpdatedAt, setLastUpdatedAt] = useState<number>(0);
const initialized = useRef(false)
const lastRefreshedAt = useRef(0)
// FIXME @naiba 触发了两次
useEffect(() => {
if (profile && Date.now() - lastUpdatedAt > 1000 * 60 * 5) {
console.log(profile, Date.now(), lastUpdatedAt)
getProfile().then((data) => {
setLastUpdatedAt(Date.now())
if (data && data.username !== profile.username) {
console.log('bingo', data.username);
setProfile(data)
}
}).catch(() => {
setLastUpdatedAt(Date.now())
setProfile(undefined)
})
if (initialized.current) {
return
}
initialized.current = true;
(async () => {
while (true) {
if (!profile) {
await new Promise((resolve) => setTimeout(resolve, 1000))
continue
}
if (lastRefreshedAt.current + 1000 * 60 * 10 > Date.now()) {
await new Promise((resolve) => setTimeout(resolve, 1000))
continue
}
try {
await refreshToken();
const user = await getProfile();
setProfile(user);
lastRefreshedAt.current = Date.now();
} catch (error) {
setProfile(undefined);
}
}
})();
}, [profile])
const navigate = useNavigate();

View File

@@ -15,7 +15,7 @@ import { AuthProvider } from './hooks/useAuth';
const router = createBrowserRouter([
{
path: "/dashboard/",
path: "/dashboard",
element: <AuthProvider><ProtectedRoute><Root /></ProtectedRoute></AuthProvider>,
errorElement: <ErrorPage />,
children: [

View File

@@ -66,7 +66,7 @@ export default () => {
<FormItem>
<FormLabel>Password</FormLabel>
<FormControl>
<Input placeholder="shadcn" {...field} />
<Input type="password" placeholder="shadcn" {...field} />
</FormControl>
<FormDescription>
This is your public display name.
@@ -75,7 +75,7 @@ export default () => {
</FormItem>
)}
/>
<Button type="submit">Submit</Button>
<Button type="submit">Login</Button>
</form>
</Form>
</div>

View File

@@ -7,7 +7,7 @@ export const ProtectedRoute = ({ children }: {
const { profile } = useAuth();
if (!profile && window.location.pathname !== "/dashboard/login") {
return <Navigate to="/dashboard/login" />;
return <><Navigate to="/dashboard/login" />{children}</>;
}
return children;