diff --git a/api/v1/jwt.go b/api/v1/jwt.go index a596f3c7..5599ede4 100644 --- a/api/v1/jwt.go +++ b/api/v1/jwt.go @@ -62,7 +62,7 @@ func JWTMiddleware(server *APIV1Service, next echo.HandlerFunc, secret string) e } // Skip validation for server status endpoints. - if util.HasPrefixes(path, "/api/v1/ping", "/api/v1/idp", "/api/v1/status", "/api/v1/user") && path != "/api/v1/user/me" && path != "/api/v1/user" && method == http.MethodGet { + if util.HasPrefixes(path, "/api/v1/ping", "/api/v1/idp", "/api/v1/status") && method == http.MethodGet { return next(c) } @@ -73,7 +73,7 @@ func JWTMiddleware(server *APIV1Service, next echo.HandlerFunc, secret string) e return next(c) } // When the request is not authenticated, we allow the user to access the memo endpoints for those public memos. - if util.HasPrefixes(path, "/api/v1/memo") && method == http.MethodGet { + if util.HasPrefixes(path, "/api/v1/memo", "/api/v1/user") && path != "/api/v1/user" && method == http.MethodGet { return next(c) } return echo.NewHTTPError(http.StatusUnauthorized, "Missing access token") diff --git a/api/v1/user.go b/api/v1/user.go index 67359f56..5412284a 100644 --- a/api/v1/user.go +++ b/api/v1/user.go @@ -281,8 +281,12 @@ func (s *APIV1Service) GetUserByID(c echo.Context) error { } userMessage := convertUserFromStore(user) - // data desensitize - userMessage.Email = "" + userID, ok := c.Get(userIDContextKey).(int32) + if !ok || userID != user.ID { + // Data desensitize. + userMessage.Email = "" + } + return c.JSON(http.StatusOK, userMessage) } diff --git a/web/src/helpers/api.ts b/web/src/helpers/api.ts index 9aed265b..51d4699f 100644 --- a/web/src/helpers/api.ts +++ b/web/src/helpers/api.ts @@ -18,7 +18,7 @@ export function vacuumDatabase() { } export function signin(username: string, password: string, remember: boolean) { - return axios.post("/api/v1/auth/signin", { + return axios.post("/api/v1/auth/signin", { username, password, remember, @@ -26,7 +26,7 @@ export function signin(username: string, password: string, remember: boolean) { } export function signinWithSSO(identityProviderId: IdentityProviderId, code: string, redirectUri: string) { - return axios.post("/api/v1/auth/signin/sso", { + return axios.post("/api/v1/auth/signin/sso", { identityProviderId, code, redirectUri, @@ -34,7 +34,7 @@ export function signinWithSSO(identityProviderId: IdentityProviderId, code: stri } export function signup(username: string, password: string) { - return axios.post("/api/v1/auth/signup", { + return axios.post("/api/v1/auth/signup", { username, password, }); @@ -44,14 +44,14 @@ export function signout() { return axios.post("/api/v1/auth/signout"); } -export function getMyselfUser() { - return axios.get("/api/v1/user/me"); -} - export function getUserList() { return axios.get("/api/v1/user"); } +export function getUserById(id: number) { + return axios.get(`/api/v1/user/${id}`); +} + export function upsertUserSetting(upsert: UserSettingUpsert) { return axios.post(`/api/v1/user/setting`, upsert); } diff --git a/web/src/pages/AuthCallback.tsx b/web/src/pages/AuthCallback.tsx index 4706e3ea..2d340b1e 100644 --- a/web/src/pages/AuthCallback.tsx +++ b/web/src/pages/AuthCallback.tsx @@ -5,6 +5,7 @@ import { useSearchParams } from "react-router-dom"; import Icon from "@/components/Icon"; import * as api from "@/helpers/api"; import { absolutifyLink } from "@/helpers/utils"; +import useNavigateTo from "@/hooks/useNavigateTo"; import { useUserStore } from "@/store/module"; import { useTranslate } from "@/utils/i18n"; @@ -15,6 +16,7 @@ interface State { const AuthCallback = () => { const t = useTranslate(); + const navigateTo = useNavigateTo(); const [searchParams] = useSearchParams(); const userStore = useUserStore(); const [state, setState] = useState({ @@ -32,14 +34,15 @@ const AuthCallback = () => { if (identityProviderId) { api .signinWithSSO(identityProviderId, code, redirectUri) - .then(async () => { + .then(async ({ data: user }) => { setState({ loading: false, errorMessage: "", }); - const user = await userStore.doSignIn(); if (user) { - window.location.href = "/"; + userStore.setCurrentUser(user); + await userStore.fetchCurrentUser(); + navigateTo("/"); } else { toast.error(t("message.login-failed")); } diff --git a/web/src/pages/SignIn.tsx b/web/src/pages/SignIn.tsx index 8475dfd5..39eedf7c 100644 --- a/web/src/pages/SignIn.tsx +++ b/web/src/pages/SignIn.tsx @@ -7,11 +7,13 @@ import LocaleSelect from "@/components/LocaleSelect"; import * as api from "@/helpers/api"; import { absolutifyLink } from "@/helpers/utils"; import useLoading from "@/hooks/useLoading"; +import useNavigateTo from "@/hooks/useNavigateTo"; import { useGlobalStore, useUserStore } from "@/store/module"; import { useTranslate } from "@/utils/i18n"; const SignIn = () => { const t = useTranslate(); + const navigateTo = useNavigateTo(); const globalStore = useGlobalStore(); const userStore = useUserStore(); const actionBtnLoadingState = useLoading(false); @@ -72,10 +74,11 @@ const SignIn = () => { try { actionBtnLoadingState.setLoading(); - await api.signin(username, password, remember); - const user = await userStore.doSignIn(); + const { data: user } = await api.signin(username, password, remember); if (user) { - window.location.href = "/"; + userStore.setCurrentUser(user); + await userStore.fetchCurrentUser(); + navigateTo("/"); } else { toast.error(t("message.login-failed")); } diff --git a/web/src/pages/SignUp.tsx b/web/src/pages/SignUp.tsx index e7df371e..9b560d41 100644 --- a/web/src/pages/SignUp.tsx +++ b/web/src/pages/SignUp.tsx @@ -6,11 +6,13 @@ import AppearanceSelect from "@/components/AppearanceSelect"; import LocaleSelect from "@/components/LocaleSelect"; import * as api from "@/helpers/api"; import useLoading from "@/hooks/useLoading"; +import useNavigateTo from "@/hooks/useNavigateTo"; import { useGlobalStore, useUserStore } from "@/store/module"; import { useTranslate } from "@/utils/i18n"; const SignUp = () => { const t = useTranslate(); + const navigateTo = useNavigateTo(); const globalStore = useGlobalStore(); const userStore = useUserStore(); const actionBtnLoadingState = useLoading(false); @@ -52,10 +54,11 @@ const SignUp = () => { try { actionBtnLoadingState.setLoading(); - await api.signup(username, password); - const user = await userStore.doSignIn(); + const { data: user } = await api.signup(username, password); if (user) { - window.location.href = "/"; + userStore.setCurrentUser(user); + await userStore.fetchCurrentUser(); + navigateTo("/"); } else { toast.error(t("message.signup-failed")); } diff --git a/web/src/store/module/user.ts b/web/src/store/module/user.ts index 39454570..d95319f0 100644 --- a/web/src/store/module/user.ts +++ b/web/src/store/module/user.ts @@ -58,10 +58,8 @@ export const initialUserState = async () => { store.dispatch(setHost(convertResponseModelUser(systemStatus.host))); } - const { data } = await api.getMyselfUser(); - if (data) { - const user = convertResponseModelUser(data); - store.dispatch(setUser(user)); + const user = await fetchCurrentUser(); + if (user) { if (user.setting.locale) { store.dispatch(setLocale(user.setting.locale)); } @@ -72,18 +70,21 @@ export const initialUserState = async () => { } }; -const doSignIn = async () => { - const { data: user } = await api.getMyselfUser(); - if (user) { - store.dispatch(setUser(convertResponseModelUser(user))); - } else { - doSignOut(); - } - return user; -}; - const doSignOut = async () => { await api.signout(); + localStorage.removeItem("userId"); +}; + +const fetchCurrentUser = async () => { + const userId = localStorage.getItem("userId"); + if (userId) { + const { data } = await api.getUserById(Number(userId)); + const user = convertResponseModelUser(data); + if (user) { + store.dispatch(setUser(user)); + return user; + } + } }; export const useUserStore = () => { @@ -94,14 +95,17 @@ export const useUserStore = () => { getState: () => { return store.getState().user; }, - doSignIn, doSignOut, + fetchCurrentUser, + setCurrentUser: async (user: User) => { + localStorage.setItem("userId", String(user.id)); + }, upsertUserSetting: async (key: string, value: any) => { await api.upsertUserSetting({ key: key as any, value: JSON.stringify(value), }); - await doSignIn(); + await fetchCurrentUser(); }, upsertLocalSetting: async (localSetting: LocalSetting) => { storage.set({ localSetting });