我试图在Vue 3 js应用程序中检查路由的授权。这个想法是授权应该根据用户的角色(NavGuard)来定义。出于这个原因,当用户登录时(JWT令牌),我将他的角色添加到Pinia存储的状态(useUserStore)。
我已经阅读了有关"Using a store outside of a component"的文档,当用户登录并被重定向到主页时,它实际上是工作的。如果我console.log(store)
,我可以看到用户的角色。
但是,每当我导航到另一个页面时,console.logged状态就是初始状态(所有值都为null)。我猜问题是路由器在状态准备好之前就加载了。
import NotFoundView from '@/views/public/NotFoundView.vue'
import { useUserStore } from '@/stores/user'
import pinia from "@/stores/store.js";
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
name: 'home',
component: HomeView
},
{
path: '/about',
name: 'about',
component: AboutView
},
{
path: '/:pathMatch(.*)*',
name: 'NotFound',
component: NotFoundView
},
]
})
router.beforeEach(async (to, from) => {
const store = await useUserStore();
console.log(store.user)
})
export default router
Main.js
import { createApp } from 'vue'
import store from '@/stores/store'
import App from '@/App.vue'
import router from '@/router'
import axios from 'axios'
axios.defaults.baseURL = 'http://127.0.0.1:8000'
const app = createApp(App)
app.use(store)
app.use(router, axios)
router.isReady().then(() => {
app.mount("#app");
});
store.js
import { createPinia } from "pinia";
const pinia = createPinia();
export default pinia;
user.js
import { defineStore } from 'pinia'
import axios from 'axios'
export const useUserStore = defineStore('user', {
id: 'user',
state: () => {
return {
user: {
isAuthenticated: false,
id: null,
name: null,
email: null,
access: null,
refresh: null,
role: null,
}
}
},
actions: {
initStore() {
console.log('initStore')
if (localStorage.getItem('user.access')) {
this.user.access = localStorage.getItem('user.access')
this.user.refresh = localStorage.getItem('user.refresh')
this.user.id = localStorage.getItem('user.id')
this.user.name = localStorage.getItem('user.name')
this.user.email = localStorage.getItem('user.email')
this.user.isAuthenticated = true
this.refreshToken()
console.log('Initialized user:', this.user)
}
},
setToken(data) {
console.log('setToken', data)
this.user.access = data.access
this.user.refresh = data.refresh
this.user.isAuthenticated = true
localStorage.setItem('user.access', data.access)
localStorage.setItem('user.refresh', data.refresh)
},
removeToken() {
console.log('removeToken')
this.user.refresh = null
this.user.access = null
this.user.isAuthenticated = false
this.user.id = false
this.user.name = false
this.user.email = false
localStorage.setItem('user.access', '')
localStorage.setItem('user.refresh', '')
localStorage.setItem('user.id', '')
localStorage.setItem('user.name', '')
localStorage.setItem('user.email', '')
},
setUserInfo(user) {
console.log('setUserInfo', user)
this.user.id = user.id
this.user.name = user.name
this.user.email = user.email
this.user.role = user.role
localStorage.setItem('user.id', this.user.id)
localStorage.setItem('user.name', this.user.name)
localStorage.setItem('user.email', this.user.email)
localStorage.setItem('user.role', this.user.role)
console.log('User', this.user)
},
refreshToken() {
axios.post('/api/refresh/', {
refresh: this.user.refresh
})
.then((response) => {
this.user.access = response.data.access
localStorage.setItem('user.access', response.data.access)
axios.defaults.headers.common["Authorization"] = "Bearer " + response.data.access
})
.catch((error) => {
console.log(error)
this.removeToken()
})
}
},
})
LogIn.vue
<template>
<div class="max-w-7xl max-h-screen h-[740px] mx-auto grid grid-cols-2 gap-24 mt-6 m-10">
<div class="main-left">
<div class="p-4 h-full">
<div class="p-12 bg-hero-mutrah h-full rounded-lg bg-cover">
</div>
</div>
</div>
<div class="main-right">
<div class="p-12 bg-white rounded-lg">
<form class="space-y-6" v-on:submit.prevent="submitForm">
<div>
<label>Email</label>
<input type="email" v-model="form.email" placeholder="Your email address"
class="w-full mt-2 py-4 px-6 border border-gray-200 rounded-lg">
</div>
<div>
<label>Password</label>
<input type="password" v-model="form.password" placeholder="Password"
class="w-full mt-2 py-4 px-6 border border-gray-200 rounded-lg">
</div>
<div>
<button class="py-4 px-6 bg-orange-500 font-bold text-white rounded-lg">Log In</button>
</div>
</form>
</div>
</div>
</div>
</template>
<script>
import axios from 'axios'
import { useUserStore } from '@/stores/user'
import { useToastStore } from '@/stores/toast'
export default {
setup() {
const userStore = useUserStore()
const toastStore = useToastStore()
return {
userStore,
toastStore
}
},
data() {
return {
form: {
email: '',
password: '',
},
errors: []
}
},
methods: {
async submitForm() {
this.errors = []
if (this.form.email === '') {
this.errors.push('Your email is missing')
}
if (this.form.password === '') {
this.errors.push('Your password is missing')
}
if (this.errors.length === 0) {
await axios
.post('/api/login/', this.form)
.then(response => {
console.log({ 'message': response.data })
this.userStore.setToken(response.data)
axios.defaults.headers.common["Authorization"] = `Bearer ${response.data.access}`;
})
.catch(error => {
this.toastStore.showToast(5000, 'Oops we could not find matching credentials', 'bg-red-300')
})
await axios
.get('/api/me/')
.then(response => {
console.log({ 'message': response })
this.userStore.setUserInfo(response.data)
this.userStore.initStore(response.data)
this.$router.push('/')
})
.catch(error => {
console.log('error', error)
})
}
else {
if (this.errors == 'Your email is missing')
this.toastStore.showToast(5000, 'Your email is missing', 'bg-red-300')
if (this.errors == 'Your password is missing')
this.toastStore.showToast(5000, 'Your password is missing', 'bg-red-300')
}
}
},
}
</script>
这段代码是工作,因为我有正确的预期行为时,用户登录。但是我需要在每个页面之前检查用户角色,而不仅仅是在登录时。
有什么建议吗?
感谢您花时间阅读!
1条答案
按热度按时间nx7onnlm1#
看起来你在Vue 3和Pinia上遇到了一个问题,那就是在导航到每个页面之前检查用户的角色。你是正确的,问题可能源于路由器在用户状态准备好之前被加载。要解决这个问题,您可以将Vue Router的beforeEach导航保护与Pinia的商店结合使用。
下面是代码的修改版本,它应该可以帮助您实现所需的行为:
1.更新路由器配置:
更新你的user.js商店:在user.js存储中,似乎有一个initStore操作来初始化用户状态。您可以在应用启动时调用此操作,以确保在任何路线导航之前初始化用户状态。
通过遵循这些步骤,您的Vue 3应用程序现在应该在每个页面导航之前正确检查用户的角色,即使在登录之后也是如此。请记住,使用基于用户角色的实际授权检查来替换router.beforeEach保护中的占位符逻辑。