From 9b5500305f8f4b43bdf1129c7be12c4870190fd8 Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Sun, 28 Jan 2024 00:42:02 +0800 Subject: [PATCH] :sparkles: User info --- pkg/server/auth.go | 1 + pkg/server/profiles_api.go | 12 ++++++ pkg/server/startup.go | 1 + view/src/layouts/RootLayout.tsx | 24 +++++++++--- view/src/layouts/shared/Navbar.tsx | 7 +++- view/src/pages/auth/login.tsx | 2 + view/src/pages/dashboard.tsx | 4 +- view/src/stores/userinfo.ts | 62 ++++++++++++++++++++++++++++++ view/tsconfig.json | 2 +- 9 files changed, 106 insertions(+), 9 deletions(-) create mode 100644 pkg/server/profiles_api.go create mode 100644 view/src/stores/userinfo.ts diff --git a/pkg/server/auth.go b/pkg/server/auth.go index f938f5d..84d97b7 100644 --- a/pkg/server/auth.go +++ b/pkg/server/auth.go @@ -28,6 +28,7 @@ var auth = keyauth.New(keyauth.Config{ return false, err } + c.Locals("principal", user) c.Locals("permissions", user.Permissions.Data()) return true, nil diff --git a/pkg/server/profiles_api.go b/pkg/server/profiles_api.go new file mode 100644 index 0000000..8d82612 --- /dev/null +++ b/pkg/server/profiles_api.go @@ -0,0 +1,12 @@ +package server + +import ( + "code.smartsheep.studio/hydrogen/passport/pkg/models" + "github.com/gofiber/fiber/v2" +) + +func aboutMe(c *fiber.Ctx) error { + user := c.Locals("principal").(models.Account) + + return c.JSON(user) +} diff --git a/pkg/server/startup.go b/pkg/server/startup.go index b77063d..559dd91 100644 --- a/pkg/server/startup.go +++ b/pkg/server/startup.go @@ -21,6 +21,7 @@ func NewServer() { api := A.Group("/api").Name("API") { + api.Get("/users/me", auth, aboutMe) api.Post("/users", doRegister) api.Put("/auth", startChallenge) diff --git a/view/src/layouts/RootLayout.tsx b/view/src/layouts/RootLayout.tsx index b28b6f8..d78be5c 100644 --- a/view/src/layouts/RootLayout.tsx +++ b/view/src/layouts/RootLayout.tsx @@ -1,11 +1,25 @@ import Navbar from "./shared/Navbar.tsx"; +import { readProfiles } from "../stores/userinfo.ts"; +import { createSignal, Show } from "solid-js"; export default function RootLayout(props: any) { - return ( -
- + const [ready, setReady] = createSignal(false); -
{props.children}
-
+ readProfiles().then(() => setReady(true)); + + return ( + +
+ +
+ + }> +
+ + +
{props.children}
+
+
); } \ No newline at end of file diff --git a/view/src/layouts/shared/Navbar.tsx b/view/src/layouts/shared/Navbar.tsx index baba66a..3edf5f9 100644 --- a/view/src/layouts/shared/Navbar.tsx +++ b/view/src/layouts/shared/Navbar.tsx @@ -1,4 +1,5 @@ -import { For } from "solid-js"; +import { For, Show } from "solid-js"; +import { userinfo } from "../../stores/userinfo.ts"; interface MenuItem { label: string; @@ -57,7 +58,9 @@ export default function Navbar() { ); diff --git a/view/src/pages/auth/login.tsx b/view/src/pages/auth/login.tsx index 8ece1bb..8b4db99 100644 --- a/view/src/pages/auth/login.tsx +++ b/view/src/pages/auth/login.tsx @@ -1,3 +1,4 @@ +import { readProfiles } from "../../stores/userinfo.ts"; import { useNavigate } from "@solidjs/router"; import { createSignal, For, Match, Show, Switch } from "solid-js"; import Cookie from "universal-cookie"; @@ -85,6 +86,7 @@ export default function Login() { const data = await res.json(); if (data["is_finished"]) { await grantToken(data["session"]["grant_token"]); + await readProfiles(); navigate("/"); } else { setError(null); diff --git a/view/src/pages/dashboard.tsx b/view/src/pages/dashboard.tsx index 0fe0ebf..387284b 100644 --- a/view/src/pages/dashboard.tsx +++ b/view/src/pages/dashboard.tsx @@ -1,7 +1,9 @@ +import { userinfo } from "../stores/userinfo.ts"; + export default function Dashboard() { return (
-

Welcome, undefined

+

Welcome, {userinfo.displayName}

What's a nice day!

) diff --git a/view/src/stores/userinfo.ts b/view/src/stores/userinfo.ts new file mode 100644 index 0000000..f5ba90f --- /dev/null +++ b/view/src/stores/userinfo.ts @@ -0,0 +1,62 @@ +import { createStore } from "solid-js/store"; +import Cookie from "universal-cookie"; + +const [userinfo, setUserinfo] = createStore({ + isLoggedIn: false, + displayName: "Citizen", + profiles: null, + meta: null +}); + +function checkLoggedIn(): boolean { + return new Cookie().get("access_token"); +} + +export function getAtk(): string { + return new Cookie().get("access_token"); +} + +export async function refreshAtk() { + const rtk = new Cookie().get("refresh_token"); + + const res = await fetch("/api/auth/token", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + code: rtk, + grant_type: "refresh_token" + }) + }); + if (res.status !== 200) { + throw new Error(await res.text()); + } else { + const data = await res.json(); + new Cookie().set("access_token", data["access_token"], { path: "/" }); + new Cookie().set("refresh_token", data["refresh_token"], { path: "/" }); + } +} + +export async function readProfiles() { + if (!checkLoggedIn()) return; + + const res = await fetch("/api/users/me", { + headers: { "Authorization": `Bearer ${getAtk()}` } + }); + + if (res.status !== 200) { + // Auto retry after refresh access token + await refreshAtk(); + return await readProfiles(); + } + + const data = await res.json(); + + setUserinfo({ + isLoggedIn: true, + displayName: data["nick"], + profiles: null, + meta: data + }); +} + +export { userinfo }; \ No newline at end of file diff --git a/view/tsconfig.json b/view/tsconfig.json index 3999958..b5ebb60 100644 --- a/view/tsconfig.json +++ b/view/tsconfig.json @@ -3,7 +3,7 @@ "target": "ES2020", "useDefineForClassFields": true, "module": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], + "lib": ["ES2020", "ES2015", "DOM", "DOM.Iterable"], "skipLibCheck": true, /* Bundler mode */