feat(auth): implement user logout functionality
- Add logout action to delete auth cookie and reset user state - Create logout form with enhanced submit handling - Integrate toast notifications for logout feedback - Update sidebar to include logout button with form submission - Remove unnecessary console log in layout server load - Clean up JWT parsing logic in hooks server file - Add new LogoutButton component (currently empty)
This commit is contained in:
@@ -7,10 +7,7 @@ export const handle: Handle = async ({ event, resolve}) =>{
|
|||||||
const authorization = event.cookies.get(COOKIE_TOKEN_KEY);
|
const authorization = event.cookies.get(COOKIE_TOKEN_KEY);
|
||||||
if (authorization){
|
if (authorization){
|
||||||
const split = authorization?.split(' ');
|
const split = authorization?.split(' ');
|
||||||
|
|
||||||
const token = split[1];
|
const token = split[1];
|
||||||
|
|
||||||
|
|
||||||
const jwt = parseJwt<JwtPayload>(token);
|
const jwt = parseJwt<JwtPayload>(token);
|
||||||
|
|
||||||
if (jwt){
|
if (jwt){
|
||||||
|
|||||||
8
src/lib/components/button/LogoutButton.svelte
Normal file
8
src/lib/components/button/LogoutButton.svelte
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { enhance } from '$app/forms';
|
||||||
|
import { getContext } from 'svelte';
|
||||||
|
import { TOAST_KEY, type ToastState } from '$lib/stores/toast.svelte.ts';
|
||||||
|
import Icon from '$lib/components/icon/Icon.svelte'; // 假设你的路径
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
@@ -4,7 +4,9 @@
|
|||||||
import { fly, fade } from 'svelte/transition';
|
import { fly, fade } from 'svelte/transition';
|
||||||
import Icon from '$lib/components/icon/Icon.svelte';
|
import Icon from '$lib/components/icon/Icon.svelte';
|
||||||
import type { NavItem, ProcessedNavItem } from '$lib/types/layout';
|
import type { NavItem, ProcessedNavItem } from '$lib/types/layout';
|
||||||
|
import { getContext } from 'svelte';
|
||||||
|
import { TOAST_KEY, type ToastState } from '$lib/stores/toast.svelte.ts';
|
||||||
|
import { enhance } from '$app/forms';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -104,7 +106,26 @@
|
|||||||
// 使用 $derived 动态计算,类型自动推断为 ProcessedNavItem[]
|
// 使用 $derived 动态计算,类型自动推断为 ProcessedNavItem[]
|
||||||
let navItems = $derived(processNavItems(rawNavItems, page.url.pathname));
|
let navItems = $derived(processNavItems(rawNavItems, page.url.pathname));
|
||||||
|
|
||||||
|
// 获取 Toast 以便提示用户
|
||||||
|
const toast = getContext<ToastState>(TOAST_KEY);
|
||||||
|
|
||||||
|
// 处理提交结果的回调
|
||||||
|
const handleLogout = () => {
|
||||||
|
toast.info('正在退出登录...');
|
||||||
|
return async ({ result, update }) => {
|
||||||
|
|
||||||
|
// result.type 可能是 'redirect', 'success', 'failure'
|
||||||
|
if (result.type === 'redirect') {
|
||||||
|
toast.success('您已安全退出');
|
||||||
|
}
|
||||||
|
|
||||||
|
// update() 会触发默认行为(也就是执行 redirect 跳转)
|
||||||
|
await update();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
let logoutForm: HTMLFormElement;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- 定义递归 Snippet,显式指定类型 -->
|
<!-- 定义递归 Snippet,显式指定类型 -->
|
||||||
@@ -213,11 +234,23 @@
|
|||||||
<a href="/app/settings"><Icon id="settings" size="16" /> 设置</a>
|
<a href="/app/settings"><Icon id="settings" size="16" /> 设置</a>
|
||||||
</li>
|
</li>
|
||||||
<div class="divider my-1"></div>
|
<div class="divider my-1"></div>
|
||||||
<li>
|
|
||||||
<button class="text-error" >
|
<li class="">
|
||||||
|
<button
|
||||||
|
class="text-error w-full text-left flex items-center gap-2"
|
||||||
|
on:click={() => logoutForm.requestSubmit()}
|
||||||
|
>
|
||||||
<Icon id="sign-out" size="16" /> 退出登录
|
<Icon id="sign-out" size="16" /> 退出登录
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
|
<form
|
||||||
|
action="/auth/logout"
|
||||||
|
method="POST"
|
||||||
|
use:enhance={handleLogout}
|
||||||
|
bind:this={logoutForm}
|
||||||
|
hidden
|
||||||
|
>
|
||||||
|
</form>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import { COOKIE_THEME_KEY } from '$lib/components/constants/cookiesConstants.ts'
|
|||||||
|
|
||||||
export const load: LayoutServerLoad = async ({url,cookies,locals}) => {
|
export const load: LayoutServerLoad = async ({url,cookies,locals}) => {
|
||||||
|
|
||||||
console.log("locals",locals);
|
|
||||||
const targetPath: RouteId = '/app/dashboard';
|
const targetPath: RouteId = '/app/dashboard';
|
||||||
|
|
||||||
if (url.pathname === '/') {
|
if (url.pathname === '/') {
|
||||||
|
|||||||
17
src/routes/auth/logout/+page.server.ts
Normal file
17
src/routes/auth/logout/+page.server.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import type { Actions } from './$types';
|
||||||
|
import { redirect } from '@sveltejs/kit';
|
||||||
|
|
||||||
|
import { resolve } from '$app/paths';
|
||||||
|
|
||||||
|
import { COOKIE_TOKEN_KEY } from '$lib/components/constants/cookiesConstants.ts';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export const actions:Actions = {
|
||||||
|
default: async ({ cookies,locals}) => {
|
||||||
|
cookies.delete(COOKIE_TOKEN_KEY,{path:'/'});
|
||||||
|
locals.user = null;
|
||||||
|
|
||||||
|
throw redirect(302, resolve('/'));
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user