Kill Sessions

This commit is contained in:
LittleSheep 2024-01-30 18:18:25 +08:00
parent 2a32c8b2f6
commit e87da59026
4 changed files with 53 additions and 6 deletions

View File

@ -55,6 +55,20 @@ func getEvents(c *fiber.Ctx) error {
}) })
} }
func killSession(c *fiber.Ctx) error {
user := c.Locals("principal").(models.Account)
id, _ := c.ParamsInt("sessionId", 0)
if err := database.C.Delete(&models.AuthSession{}, &models.AuthSession{
BaseModel: models.BaseModel{ID: uint(id)},
AccountID: user.ID,
}).Error; err != nil {
return fiber.NewError(fiber.StatusNotFound, err.Error())
}
return c.SendStatus(fiber.StatusOK)
}
func doRegister(c *fiber.Ctx) error { func doRegister(c *fiber.Ctx) error {
var data struct { var data struct {
Name string `json:"name"` Name string `json:"name"`

View File

@ -26,6 +26,7 @@ func NewServer() {
{ {
api.Get("/users/me", auth, getPrincipal) api.Get("/users/me", auth, getPrincipal)
api.Get("/users/me/events", auth, getEvents) api.Get("/users/me/events", auth, getEvents)
api.Delete("/users/me/sessions/:sessionId", auth, killSession)
api.Post("/users", doRegister) api.Post("/users", doRegister)
api.Post("/users/me/confirm", doRegisterConfirm) api.Post("/users/me/confirm", doRegisterConfirm)

View File

@ -1,4 +1,4 @@
import { getAtk, useUserinfo } from "../stores/userinfo.tsx"; import { getAtk, readProfiles, useUserinfo } from "../stores/userinfo.tsx";
import { createSignal, For, Show } from "solid-js"; import { createSignal, For, Show } from "solid-js";
export default function DashboardPage() { export default function DashboardPage() {
@ -20,6 +20,7 @@ export default function DashboardPage() {
const [eventCount, setEventCount] = createSignal(0); const [eventCount, setEventCount] = createSignal(0);
const [error, setError] = createSignal<string | null>(null); const [error, setError] = createSignal<string | null>(null);
const [submitting, setSubmitting] = createSignal(false);
async function readEvents() { async function readEvents() {
const res = await fetch("/api/users/me/events?take=10", { const res = await fetch("/api/users/me/events?take=10", {
@ -34,6 +35,21 @@ export default function DashboardPage() {
} }
} }
async function killSession(item: any) {
setSubmitting(true);
const res = await fetch(`/api/users/me/sessions/${item.id}`, {
method: "DELETE",
headers: { Authorization: `Bearer ${getAtk()}` }
});
if (res.status !== 200) {
setError(await res.text());
} else {
await readProfiles();
setError(null);
}
setSubmitting(false);
}
readEvents(); readEvents();
return ( return (
@ -160,6 +176,7 @@ export default function DashboardPage() {
<th>Third Client</th> <th>Third Client</th>
<th>Audiences</th> <th>Audiences</th>
<th>Date</th> <th>Date</th>
<th></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@ -169,6 +186,16 @@ export default function DashboardPage() {
<td>{item.client_id ? "Linked" : "Non-linked"}</td> <td>{item.client_id ? "Linked" : "Non-linked"}</td>
<td>{item.audiences?.join(", ")}</td> <td>{item.audiences?.join(", ")}</td>
<td>{new Date(item.created_at).toLocaleString()}</td> <td>{new Date(item.created_at).toLocaleString()}</td>
<td class="py-0">
<button class="btn btn-sm btn-square btn-error" disabled={submitting()}
onClick={() => killSession(item)}>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="h-5 w-5">
<path
d="M256 48C141.31 48 48 141.31 48 256s93.31 208 208 208s208-93.31 208-208S370.69 48 256 48zm80 224H176a16 16 0 0 1 0-32h160a16 16 0 0 1 0 32z"
fill="currentColor"></path>
</svg>
</button>
</td>
</tr>} </tr>}
</For> </For>
</tbody> </tbody>

View File

@ -36,7 +36,7 @@ export async function refreshAtk() {
}) })
}); });
if (res.status !== 200) { if (res.status !== 200) {
throw new Error(await res.text()); console.error(await res.text())
} else { } else {
const data = await res.json(); const data = await res.json();
new Cookie().set("access_token", data["access_token"], { path: "/" }); new Cookie().set("access_token", data["access_token"], { path: "/" });
@ -48,7 +48,7 @@ function checkLoggedIn(): boolean {
return new Cookie().get("access_token"); return new Cookie().get("access_token");
} }
export async function readProfiles() { export async function readProfiles(recovering = true) {
if (!checkLoggedIn()) return; if (!checkLoggedIn()) return;
const res = await fetch("/api/users/me", { const res = await fetch("/api/users/me", {
@ -56,9 +56,14 @@ export async function readProfiles() {
}); });
if (res.status !== 200) { if (res.status !== 200) {
// Auto retry after refresh access token if (recovering) {
await refreshAtk(); // Auto retry after refresh access token
return await readProfiles(); await refreshAtk();
return await readProfiles(false);
} else {
clearUserinfo();
window.location.reload();
}
} }
const data = await res.json(); const data = await res.json();