![](/img/trans.png)
[英]Sapper session not setting properly in production build without page reload
[英]Svelte Sapper retain session on page refresh (reload)
我最近才開始使用svelte
和sapper
,即使用戶刷新頁面,我也試圖保留存儲的會話。 (我希望這可以做到)。
這個想法是用戶可以登錄,並作為經過身份驗證的用戶重定向到主頁。 但是當我在瀏覽器中點擊刷新時,會話是空的,用戶必須重新進行登錄過程。
有任何想法嗎?
到目前為止,我找不到解決方案。 在此過程中涉及的一些文件下方。
server.js
import sirv from "sirv";
import polka from "polka";
import compression from "compression";
import * as sapper from "@sapper/server";
import bodyParser from "body-parser";
import session from "express-session";
import sessionFileStore from "session-file-store";
const { PORT, NODE_ENV } = process.env;
const dev = NODE_ENV === "development";
const FileStore = sessionFileStore(session);
polka()
.use(
bodyParser.json(),
session({
secret: "secret",
resave: false,
saveUninitialized: true,
cookie: {
maxAge: 31536000,
},
store: new FileStore({
path: process.env.NOW ? `/tmp/sessions` : `.sessions`,
}),
})
)
.use(
compression({ threshold: 0 }),
sirv("static", { dev }),
sapper.middleware({
session: (req) => ({
user: req.session && req.session.user,
}),
})
)
.listen(PORT, (err) => {
if (err) console.log("error", err);
});
login.svelte
<script context="module">
export async function preload({ params }, { user }) {
if (user) {
this.redirect(302, `/`);
}
}
</script>
<script>
import { goto, stores } from "@sapper/app";
import api from "../api.js";
import Button from "../components/Button.svelte";
import Input from "../components/Input.svelte";
import InputPassword from "../components/InputPassword.svelte";
let errors;
let email;
let password;
let disabled;
const { session } = stores();
const handleSubmit = async () => {
try {
errors = null;
disabled = true;
await api.get("/csrf-cookie");
const authToken = await api.post("/login", { email, password });
api.defaults.headers.common["Authorization"] = `Bearer ${authToken.data}`;
const user = await api.get("/me");
session.set({ user: user.data });
disabled = false;
goto("/");
} catch (e) {
errors = e;
disabled = false;
}
};
</script>
<style>
.login-form {
max-width: 35em;
margin: 5% auto;
padding: 2em;
background: rgba(233, 233, 233, 0.5);
border: 1px solid rgba(151, 151, 151, 0.5);
border-radius: 5px;
}
.form-title {
margin-top: 0;
font-size: 1.2em;
}
.error-block {
color: red;
}
</style>
<svelte:head>
<title>Login</title>
</svelte:head>
<div class="login-form">
<h3 class="form-title">Login</h3>
<form on:submit|preventDefault={handleSubmit}>
<Input placeholder="Username" id="email" bind:value={email} />
<InputPassword placeholder="Password" id="password" bind:value={password} />
<Button {disabled} type="submit">Login</Button>
{#if errors}<span class="error-block">{errors}</span>{/if}
</form>
</div>
index.svelte
<script context="module">
export async function preload({ params }, { user }) {
console.log(user); // undefined
if (!user) {
this.redirect(302, `/login`);
}
}
</script>
<h1>Dashboard</h1>
我正在使用Laravel 8 sanctum
進行身份驗證。
不知道我還需要提供什么才能深入了解這個問題。
看起來好像您從sapper realworld項目中提取了大部分代碼(如果我錯了,請糾正我),但是您忘記實現服務器端“api 路由”以將新登錄的用戶添加到會話中。
在實際項目中,當用戶登錄時,會向服務器端/auth/login
路由發出 POST 請求,該請求由以下函數提供:
import * as api from 'api.js';
export function post(req, res) {
const user = req.body;
api.post('users/login', { user }).then(response => {
if (response.user) req.session.user = response.user;
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify(response));
});
}
這個函數的作用是:
/users/login
端點user
對象,則將該對象存儲到服務器端會話中考慮到您顯然不是使用真實世界的項目 API 進行身份驗證,而是使用您自己的身份驗證過程,您必須添加的是與上述類似的服務器端路由,但它將:
考慮到您在代碼中用於在客戶端設置用戶的 API 調用,該函數將如下所示(例如將該文件保存為/routes/auth/login.js
):
import * as api from 'api.js';
export async function post(req, res) {
const { email, password } = req.body;
const authToken = await api.post("/login", { email, password });
api.defaults.headers.common["Authorization"] = `Bearer ${authToken.data}`;
const user = await api.get("/me");
if (user) req.session.user = user.data;
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify(user));
}
並且login.svelte
文件中的handleSubmit
方法變為:
const handleSubmit = async () => {
try {
errors = null;
disabled = true;
// substitute your auth API request chain with a proxy request to
// the server-side API where you will set the server-side session user
const user = await fetch('/auth/login', {
method: 'POST',
credentials: 'include',
body: JSON.stringify({ email, password }),
headers: { 'Content-Type': 'application/json' },
})
session.set({ user: user.data });
disabled = false;
goto("/");
} catch (e) {
errors = e;
disabled = false;
}
};
請注意,在您的特定情況下,您可能還希望在會話中存儲身份驗證令牌,以避免每次向數據 API 發出經過身份驗證的請求時都必須請求新令牌。
使用 svelte localStorage:
創建一個商店,例如 myStore.js
import { writable } from 'svelte/store';
export let mystore = writable({
session: ""
});
export function setSession(session) {
mystore.set({
session: session
});
session = session; // refresh UI
}
在 routes/_layout.svelte 中訂閱它
<script>
import {mystore, setSession} from './myStore.js'
let session = setSession("A_SESSION"); // here comes the session
const unsubscribeMyStore = mystore.subscribe(value => {
session = session;
});
</script>
<A_COMPONENT bind:session={$mystore}/> // if the component exports session
在 A_COMPONENT 中使用:
<script>
export let session;
</script>
<div>
{session.session}
</div>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.