✨ User info
This commit is contained in:
parent
4f33b9e0f6
commit
9b5500305f
@ -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
|
||||
|
12
pkg/server/profiles_api.go
Normal file
12
pkg/server/profiles_api.go
Normal file
@ -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)
|
||||
}
|
@ -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)
|
||||
|
@ -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) {
|
||||
const [ready, setReady] = createSignal(false);
|
||||
|
||||
readProfiles().then(() => setReady(true));
|
||||
|
||||
return (
|
||||
<Show when={ready()} fallback={
|
||||
<div class="h-screen w-screen flex justify-center items-center">
|
||||
<div>
|
||||
<span class="loading loading-lg loading-infinity"></span>
|
||||
</div>
|
||||
</div>
|
||||
}>
|
||||
<div>
|
||||
<Navbar />
|
||||
|
||||
<main class="h-[calc(100vh-68px)]">{props.children}</main>
|
||||
</div>
|
||||
</Show>
|
||||
);
|
||||
}
|
@ -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() {
|
||||
</ul>
|
||||
</div>
|
||||
<div class="navbar-end pe-5">
|
||||
<Show when={!userinfo.isLoggedIn}>
|
||||
<a href="/auth/login" class="btn btn-sm btn-primary">Login</a>
|
||||
</Show>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -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);
|
||||
|
@ -1,7 +1,9 @@
|
||||
import { userinfo } from "../stores/userinfo.ts";
|
||||
|
||||
export default function Dashboard() {
|
||||
return (
|
||||
<div class="container mx-auto pt-12">
|
||||
<h1 class="text-2xl font-bold">Welcome, undefined</h1>
|
||||
<h1 class="text-2xl font-bold">Welcome, {userinfo.displayName}</h1>
|
||||
<p>What's a nice day!</p>
|
||||
</div>
|
||||
)
|
||||
|
62
view/src/stores/userinfo.ts
Normal file
62
view/src/stores/userinfo.ts
Normal file
@ -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 };
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user