You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue3+Vuex+Laravel环境下无法存储用户会话至Vuex求助

Vue3 + Vuex + Laravel Fortify SPA登录:用户会话无法存入Vuex,但系统提示已登录

我是Vue和Vuex新手,正在用Vue3、Vuex、Fortify、Laravel构建SPA的登录功能。现在遇到的问题是:登录完成后用户信息没有存入Vuex,但再次尝试登录时系统提示已经处于登录状态。


相关代码

Login.vue

<template>
    <div class="grid login-container">
        <div class="surface-card p-4 shadow-2 border-round w-full lg:w-6">
            <div class="text-center mb-5">
                <img src="images/blocks/logos/hyper.svg" alt="Image" height="50" class="mb-3">
                <div class="text-900 text-3xl font-medium mb-3">Velkommen tilbage</div>
                <span class="text-600 font-medium line-height-3">Har du ingen konto?</span>
                <a class="font-medium no-underline ml-2 text-blue-500 cursor-pointer">Opret her idag!</a>
            </div>

            <div>
                <Form :validation-schema="schema" @submit="onSubmit">
                    <div class="mb-2">
                        <Field name="email" v-slot="{ field, errorMessage }">
                            <label for="email" class="block text-900 font-medium mb-2">E-mail</label>
                            <InputText v-bind="field" :class="{ 'p-invalid': errorMessage }" type="text" class="w-full" aria-describedby="email-error" />
                            <small class="p-error" id="text-error">{{ errorMessage || '&nbsp;' }}</small>
                        </Field>
                    </div>

                    <div class="mb-2">
                        <Field name="password" v-slot="{ field, errorMessage }">
                            <label for="password" class="block text-900 font-medium mb-2">Kodeord</label>
                            <InputText v-bind="field" :class="{ 'p-invalid': errorMessage }" type="text" class="w-full" aria-describedby="password-error" />
                            <small class="p-error" id="text-error">{{ errorMessage || '&nbsp;' }}</small>
                        </Field>
                    </div>

                    <div class="flex align-items-center justify-content-between mb-6">
                        <div class="flex align-items-center">
                            <Checkbox id="rememberme" :binary="true" v-model="rembemberMe" class="mr-2"></Checkbox>
                            <label for="rememberme">Husk mig</label>
                        </div>
                        <a href="/reset" class="font-medium no-underline ml-2 text-blue-500 text-right cursor-pointer">Glemt koden?</a>
                    </div>

                    <Button type="submit" label="Log ind" icon="pi pi-user" class="w-full"></Button>
                </Form>
            </div>
        </div>
    </div>
</template>

<script setup>
import Checkbox from 'primevue/checkbox';
import { mapActions } from 'vuex';

import { ref } from 'vue'
import { Field, Form } from 'vee-validate';
import { da } from 'yup-locales';
import * as yup from 'yup';

const rembemberMe = ref(false)

yup.setLocale(da);

async function onSubmit(values, actions) {
    const mapActions = mapActions({
        signIn:'auth/login'
    });

    console.log(mapActions.user);
    
    await axios.get('/sanctum/csrf-cookie')

    await axios.post('/api/login', values).then(({ data }) => {
        this.signIn();
    }).catch(({ response }) => {
        console.log(response.data);
    });

    actions.resetForm();
}

const schema = yup.object({
    email: yup.string().email().required().label('E-mail'),
    password: yup.string().required().label('Kodeord'),
});
</script>

<style lang="">
</style>

resources/js/store/auth.js

import router from '../router'

export default {
    namespaced: true,
    state:{
        authenticated:false,
        user:{}
    },
    getters:{
        authenticated(state){
            return state.authenticated
        },
        user(state){
            return state.user
        }
    },
    mutations:{
        SET_AUTHENTICATED (state, value) {
            state.authenticated = value
        },
        SET_USER (state, value) {
            state.user = value
        }
    },
    actions:{
        login({commit}){
            return axios.get('/api/user').then(({data})=>{
                commit('SET_USER',data)
                commit('SET_AUTHENTICATED',true)
                router.push({name:'Home'})
            }).catch(({response:{data}})=>{
                commit('SET_USER',{})
                commit('SET_AUTHENTICATED',false)
            })
        },
        logout({commit}){
            commit('SET_USER',{})
            commit('SET_AUTHENTICATED',false)
        }
    }
}

resources/js/store/index.js

import { createStore } from 'vuex'
import createPersistedState from 'vuex-persistedstate'
import auth from './auth'

const store = createStore({
    plugins:[
        createPersistedState()
    ],
    modules:{
        auth
    }
})

export default store

问题现象截图

登录时提示已处于登录状态


问题原因及修复方案

1. <script setup>中mapActions使用错误

在<script setup>语法里,不能用this调用Vuex action,且你在onSubmit内部重复定义mapActions的写法完全错误。正确做法是通过useStore获取store实例,直接调用dispatch方法。

修改Login.vue的<script setup>部分:

import Checkbox from 'primevue/checkbox';
import { useStore } from 'vuex'; // 引入useStore
import { ref } from 'vue'
import { Field, Form } from 'vee-validate';
import { da } from 'yup-locales';
import * as yup from 'yup';

const rembemberMe = ref(false)
const store = useStore(); // 获取store实例

yup.setLocale(da);

async function onSubmit(values, actions) {
    await axios.get('/sanctum/csrf-cookie')

    await axios.post('/api/login', values).then(async () => {
        // 直接触发auth模块的login action
        await store.dispatch('auth/login');
    }).catch(({ response }) => {
        console.log(response.data);
    });

    actions.resetForm();
}

const schema = yup.object({
    email: yup.string().email().required().label('E-mail'),
    password: yup.string().required().label('Kodeord'),
});

2. 未等待异步action完成

原代码调用action时没有加await,导致页面跳转或状态更新可能在用户信息获取完成前执行。修改后通过await确保Vuex状态更新完成后再进行后续操作。

3. 验证Laravel后端接口

确保/api/user路由已被auth:sanctum中间件保护,在routes/api.php中配置:

Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
    return $request->user();
});

4. 确认Vuex持久化生效

修复后打开浏览器开发者工具的Application标签,查看localStorage中的vuex键,确认用户信息已被持久化存储。


内容的提问来源于stack exchange,提问作者Pulsar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 13:27:06