From 6612510d2baa31f6bb946b412351b7992b2ffbe1 Mon Sep 17 00:00:00 2001 From: crupest Date: Mon, 5 Jul 2021 22:47:38 +0800 Subject: feat: Fix #623, fix #621. --- FrontEnd/src/App.tsx | 100 ++++++++++++------------- FrontEnd/src/index.tsx | 4 - FrontEnd/src/locales/en/translation.json | 3 +- FrontEnd/src/locales/zh/translation.json | 3 +- FrontEnd/src/services/user.ts | 123 +++++++++++-------------------- 5 files changed, 93 insertions(+), 140 deletions(-) (limited to 'FrontEnd') diff --git a/FrontEnd/src/App.tsx b/FrontEnd/src/App.tsx index a4363ff5..6497b071 100644 --- a/FrontEnd/src/App.tsx +++ b/FrontEnd/src/App.tsx @@ -13,7 +13,7 @@ import TimelinePage from "./views/timeline"; import Search from "./views/search"; import AlertHost from "./views/common/alert/AlertHost"; -import { useRawUser } from "./services/user"; +import { useUser } from "./services/user"; const NoMatch: React.FC = () => { return
Ah-oh, 404!
; @@ -24,60 +24,56 @@ const LazyAdmin = React.lazy( ); function App(): ReactElement | null { - const user = useRawUser(); + const user = useUser(); - if (user === undefined) { - return ; - } else { - return ( - }> - - -
- - - {user == null ? :
} + return ( + }> + + +
+ + + {user == null ? :
} + + + + + {user != null ? ( + +
- - + ) : null} + + + + + + + + + + + + + + + + + + + {user && user.hasAdministrationPermission && ( + + - {user != null ? ( - -
- - ) : null} - - - - - - - - - - - - - - - - - - - {user && user.hasAdministrationPermission && ( - - - - )} - - - - - - - - ); - } + )} + + + + + + + + ); } export default App; diff --git a/FrontEnd/src/index.tsx b/FrontEnd/src/index.tsx index e2132de0..833e2ab8 100644 --- a/FrontEnd/src/index.tsx +++ b/FrontEnd/src/index.tsx @@ -14,8 +14,4 @@ import "./service-worker"; import App from "./App"; -import { userService } from "./services/user"; - -void userService.checkLoginState(); - ReactDOM.render(, document.getElementById("app")); diff --git a/FrontEnd/src/locales/en/translation.json b/FrontEnd/src/locales/en/translation.json index a2766b4e..da824e4a 100644 --- a/FrontEnd/src/locales/en/translation.json +++ b/FrontEnd/src/locales/en/translation.json @@ -146,8 +146,7 @@ "login": "login", "rememberMe": "Remember Me", "welcomeBack": "Welcome back!", - "verifyTokenFailed": "User login info is expired. Please login again!", - "verifyTokenFailedNetwork": "Verifying user login info failed. Please check your network and refresh page!" + "tokenInvalid": "Your authentication token is not valid any more. Please log in again!" }, "login": { "emptyUsername": "Username can't be empty.", diff --git a/FrontEnd/src/locales/zh/translation.json b/FrontEnd/src/locales/zh/translation.json index 5a5a6843..6f1346fb 100644 --- a/FrontEnd/src/locales/zh/translation.json +++ b/FrontEnd/src/locales/zh/translation.json @@ -146,8 +146,7 @@ "login": "登录", "rememberMe": "记住我", "welcomeBack": "欢迎回来!", - "verifyTokenFailed": "用户登录信息已过期,请重新登陆!", - "verifyTokenFailedNetwork": "验证用户登录信息失败,请检查网络连接并刷新页面!" + "tokenInvalid": "您的登录信息已失效,请重新登陆!" }, "login": { "emptyUsername": "用户名不能为空。", diff --git a/FrontEnd/src/services/user.ts b/FrontEnd/src/services/user.ts index 9a8e5687..2f42dd59 100644 --- a/FrontEnd/src/services/user.ts +++ b/FrontEnd/src/services/user.ts @@ -3,7 +3,7 @@ import { BehaviorSubject, Observable } from "rxjs"; import { UiLogicError } from "@/common"; -import { HttpNetworkError, setHttpToken } from "@/http/common"; +import { HttpNetworkError, setHttpToken, axios } from "@/http/common"; import { getHttpTokenClient, HttpCreateTokenBadCredentialError, @@ -11,6 +11,7 @@ import { import { getHttpUserClient, HttpUser, UserPermission } from "@/http/user"; import { pushAlert } from "./alert"; +import { AxiosError } from "axios"; interface IAuthUser extends HttpUser { token: string; @@ -58,24 +59,16 @@ export class UserService { this.userSubject.subscribe((u) => { setHttpToken(u?.token ?? null); }); - } - - private userSubject = new BehaviorSubject( - undefined - ); - - get user$(): Observable { - return this.userSubject; - } - - get currentUser(): AuthUser | null | undefined { - return this.userSubject.value; - } - async checkLoginState(): Promise { - if (this.currentUser !== undefined) { - console.warn("Already checked user. Can't check twice."); - } + axios.interceptors.response.use(undefined, (e: AxiosError) => { + if (e.isAxiosError && e.response && e.response.status === 401) { + this.userSubject.next(null); + pushAlert({ + type: "danger", + message: "user.tokenInvalid", + }); + } + }); const savedUserString = localStorage.getItem(USER_STORAGE_KEY); @@ -89,41 +82,39 @@ export class UserService { ? null : new AuthUser(savedAuthUserData, savedAuthUserData.token); - if (savedUser == null) { - this.userSubject.next(null); - return null; + if (savedUser != null) { + this.userSubject.next(savedUser); + + getHttpTokenClient() + .verify({ token: savedUser.token }) + .then( + (res) => { + const user = new AuthUser(res.user, savedUser.token); + localStorage.setItem(USER_STORAGE_KEY, JSON.stringify(user)); + this.userSubject.next(user); + }, + (error) => { + if (!(error instanceof HttpNetworkError)) { + localStorage.removeItem(USER_STORAGE_KEY); + this.userSubject.next(null); + pushAlert({ + type: "danger", + message: "user.tokenInvalid", + }); + } + } + ); } + } - this.userSubject.next(savedUser); + private userSubject = new BehaviorSubject(null); - const savedToken = savedUser.token; - try { - const res = await getHttpTokenClient().verify({ token: savedToken }); - const user = new AuthUser(res.user, savedToken); - localStorage.setItem(USER_STORAGE_KEY, JSON.stringify(user)); - this.userSubject.next(user); - pushAlert({ - type: "success", - message: "user.welcomeBack", - }); - return user; - } catch (error) { - if (error instanceof HttpNetworkError) { - pushAlert({ - type: "danger", - message: "user.verifyTokenFailedNetwork", - }); - return savedUser; - } else { - localStorage.removeItem(USER_STORAGE_KEY); - this.userSubject.next(null); - pushAlert({ - type: "danger", - message: "user.verifyTokenFailed", - }); - return null; - } - } + get user$(): Observable { + return this.userSubject; + } + + get currentUser(): AuthUser | null { + return this.userSubject.value; } async login( @@ -180,38 +171,10 @@ export class UserService { export const userService = new UserService(); -export function useRawUser(): AuthUser | null | undefined { - const [user, setUser] = useState( - userService.currentUser - ); - useEffect(() => { - const subscription = userService.user$.subscribe((u) => setUser(u)); - return () => { - subscription.unsubscribe(); - }; - }); - return user; -} - export function useUser(): AuthUser | null { - const [user, setUser] = useState(() => { - const initUser = userService.currentUser; - if (initUser === undefined) { - throw new UiLogicError( - "This is a logic error in user module. Current user can't be undefined in useUser." - ); - } - return initUser; - }); + const [user, setUser] = useState(userService.currentUser); useEffect(() => { - const sub = userService.user$.subscribe((u) => { - if (u === undefined) { - throw new UiLogicError( - "This is a logic error in user module. User emitted can't be undefined later." - ); - } - setUser(u); - }); + const sub = userService.user$.subscribe((u) => setUser(u)); return () => { sub.unsubscribe(); }; -- cgit v1.2.3