[英]Svelte Sapper retain session on page refresh (reload)
I've just recently started using svelte
and sapper
, and I'm trying to persist a stored session even when a user refreshes the page.我最近才开始使用
svelte
和sapper
,即使用户刷新页面,我也试图保留存储的会话。 (I hope this can be done). (我希望这可以做到)。
The idea is that a user can sign in, and be redirected to the homepage as an authenticated used.这个想法是用户可以登录,并作为经过身份验证的用户重定向到主页。 BUT when I hit refresh in my browser, the session is empty and user has to go through sign in process over again.
但是当我在浏览器中点击刷新时,会话是空的,用户必须重新进行登录过程。
Any Ideas?有任何想法吗?
So far I could not find a solution.到目前为止,我找不到解决方案。 Below some of the files the are involved in this process.
在此过程中涉及的一些文件下方。
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>
I'm using Laravel 8 sanctum
for Auth.我正在使用
Laravel 8 sanctum
进行身份验证。
Not sure what else I need to provide to get to the bottom of this issue.不知道我还需要提供什么才能深入了解这个问题。
It appears as though you lifted most of your code from the sapper realworld project (correct me if I'm wrong), but you forgot to implement a server-side 'api route' to add the freshly logged in user to the session.看起来好像您从sapper realworld项目中提取了大部分代码(如果我错了,请纠正我),但是您忘记实现服务器端“api 路由”以将新登录的用户添加到会话中。
In the realworld project, when the user logs in, a POST request is made to the server-side /auth/login
route, which is served by the following function:在实际项目中,当用户登录时,会向服务器端
/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));
});
}
What this function does is:这个函数的作用是:
/users/login
endpoint of the realworld project API/users/login
端点user
object, it stores that object into the server-side sessionuser
对象,则将该对象存储到服务器端会话中 Considering you're obviously NOT using the realworld project API to authenticate against, but your own auth process, what you have to add is a similar server-side route as the one above, but one that will:考虑到您显然不是使用真实世界的项目 API 进行身份验证,而是使用您自己的身份验证过程,您必须添加的是与上述类似的服务器端路由,但它将:
Considering the API calls you're using to set the user on the client side in your code, that function would look something like this (saving that file as /routes/auth/login.js
for example):考虑到您在代码中用于在客户端设置用户的 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));
}
and the handleSubmit
method in your login.svelte
file becomes:并且
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;
}
};
Note that in your particular case, you'd probably want to store the auth token in the session as well, to avoid having to request a new token every time you want to make an authenticated request to your data API.请注意,在您的特定情况下,您可能还希望在会话中存储身份验证令牌,以避免每次向数据 API 发出经过身份验证的请求时都必须请求新令牌。
Use the svelte localStorage:使用 svelte localStorage:
Create a store eg myStore.js创建一个商店,例如 myStore.js
import { writable } from 'svelte/store';
export let mystore = writable({
session: ""
});
export function setSession(session) {
mystore.set({
session: session
});
session = session; // refresh UI
}
Subscribe to it in routes/_layout.svelte在 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
Use in A_COMPONENT:在 A_COMPONENT 中使用:
<script>
export let session;
</script>
<div>
{session.session}
</div>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.