带有 Vuex 的 Firebase 身份验证 Vue Router Guard 问题
Firebase Authentication Vue Router Guard Issue w/ Vuex
我在 vue 中使用 firebase 身份验证,为了防止仪表板上导航栏中“登录”的初始闪烁(而不是身份验证时登录的用户名),我在 [=31] 中初始化 firebase =] 并将 vue 应用包装在 onAuthStateChanged 函数中。
main.js
initializeApp(firebaseConfig);
const auth = getAuth();
const app = new Vue({
router,
store,
vuetify,
render: h => h(App)
});
auth.onAuthStateChanged(user => {
console.log('firedOnAuthStateChanged');
store.dispatch("setUser", user).then(() => {
app.$mount('#app');
});
});
效果很好。我登录,直到用户通过 firebase 身份验证后页面才会加载,我用更新的用户信息更新 vuex 存储(一些来自 firebase,一些来自后端)。
我现在遇到的问题是,我想在路由器中使用 beforeEach 路由守卫,但路由守卫 运行 在 main.js 中触发 authStateChange 之前。因此,用户没有在 vuex 中设置,当我使用存储的用户状态来确定用户是否登录时,它认为他们没有登录,因为 firebase 方法还没有更新它。
authentication.js(来自 store.js 的模块)
setUser({dispatch, commit}, user) {
return new Promise((resolve, reject) => {
if(user)
{
user.getIdToken().then(token => {
commit('SET_SESSION_TOKEN', token);
console.log(token);
this._vm.$axios.get('/api/user/login',{
headers: {
'Authorization': `Bearer ${token}`
}
})
.then((response) => {
commit('SET_SESSION_USER', response.data);
resolve(response);
})
});
}
else
{
this._vm.$axios.post('/api/user/logout').then((response) => {
console.log(response);
commit('SET_SESSION_USER', null);
commit('SET_SESSION_TOKEN', null);
});
resolve();
}
})
},
router.js
router.beforeEach(async (to, from, next) => {
console.log('Is Authenticated:' +store.getters.isAuthenticated);
console.log('Session User:' +store.getters.getSessionUser);
if (to.matched.some(record => record.meta.authRequired) && !store.getters.isAuthenticated) {//!userAuth) {
next({ path: '/login'})
} else {
next();
}
});
我四处搜索,一些解决方案说在路由器中添加你的 firebase onAuthStateChanged。这确实允许路由守卫正常工作,但是重新创建了我在将该方法添加到 main.js 之前遇到的问题 - 页面闪烁并带有预登录信息。我发现其他可能性说你可以在 onAuthStateChanged 方法周围添加一个承诺并从路由器调用它。这可能行得通,但我不确定如何在 main.js 文件中使用 firebase 来实现它,该文件包裹在正在初始化的 vue 应用程序周围。
我想避免设置 cookie 或使用 localstorage 来完成这项工作,我想知道是否有某种方法可以让 firebase、vuex state 和 vue route guards 一起正常运行。
我想出了一个方法来做到这一点。登录和注销正常工作,通知在登录和注销时工作(刷新时根本不工作),用户永久登录(onAuthState 和令牌更新应处理 1 小时超时),并且页面仅在 firebase 登录完成后加载,所以没有闪烁的“登录”而不是用户名。
main.js
initializeApp(firebaseConfig);
const auth = getAuth();
let app;
auth.onAuthStateChanged(user => {
console.log('firedOnAuthStateChanged)')
store.dispatch("setUser", user).then(() => {
if (!app) {
app = new Vue({
router,
store,
vuetify,
render: h => h(App)
}).$mount('#app')
}
});
});
authentication.js(来自 store.js 的模块)
setUser({dispatch, commit}, user) {
return new Promise((resolve, reject) => {
if(user)
{
user.getIdToken().then(token => {
commit('SET_SESSION_TOKEN', token);
this._vm.$axios.get('/api/user/login',{
headers: {
'Authorization': `Bearer ${token}`
}
})
.then((response) => {
commit('SET_SESSION_USER', response.data);
resolve(response);
})
.catch(error => {
dispatch('setSnackbar', {
color: "error",
timeout: 4000,
text: 'Failed verifying token on login.'
});
reject();
});
});
}
else
{
this._vm.$axios.post('/api/user/logout').then((response) => {
commit('SET_SESSION_USER', null);
commit('SET_SESSION_TOKEN', null);
});
resolve();
}
})
}
router.js
router.beforeEach((to, from, next) => {
const auth = getAuth();
const user = auth.currentUser;
if (to.matched.some(record => record.meta.authRequired) && !user) {
next({ path: '/login'})
} else {
next();
}
});
如果您知道更有效的方法,请告诉我。
我在 vue 中使用 firebase 身份验证,为了防止仪表板上导航栏中“登录”的初始闪烁(而不是身份验证时登录的用户名),我在 [=31] 中初始化 firebase =] 并将 vue 应用包装在 onAuthStateChanged 函数中。
main.js
initializeApp(firebaseConfig);
const auth = getAuth();
const app = new Vue({
router,
store,
vuetify,
render: h => h(App)
});
auth.onAuthStateChanged(user => {
console.log('firedOnAuthStateChanged');
store.dispatch("setUser", user).then(() => {
app.$mount('#app');
});
});
效果很好。我登录,直到用户通过 firebase 身份验证后页面才会加载,我用更新的用户信息更新 vuex 存储(一些来自 firebase,一些来自后端)。
我现在遇到的问题是,我想在路由器中使用 beforeEach 路由守卫,但路由守卫 运行 在 main.js 中触发 authStateChange 之前。因此,用户没有在 vuex 中设置,当我使用存储的用户状态来确定用户是否登录时,它认为他们没有登录,因为 firebase 方法还没有更新它。
authentication.js(来自 store.js 的模块)
setUser({dispatch, commit}, user) {
return new Promise((resolve, reject) => {
if(user)
{
user.getIdToken().then(token => {
commit('SET_SESSION_TOKEN', token);
console.log(token);
this._vm.$axios.get('/api/user/login',{
headers: {
'Authorization': `Bearer ${token}`
}
})
.then((response) => {
commit('SET_SESSION_USER', response.data);
resolve(response);
})
});
}
else
{
this._vm.$axios.post('/api/user/logout').then((response) => {
console.log(response);
commit('SET_SESSION_USER', null);
commit('SET_SESSION_TOKEN', null);
});
resolve();
}
})
},
router.js
router.beforeEach(async (to, from, next) => {
console.log('Is Authenticated:' +store.getters.isAuthenticated);
console.log('Session User:' +store.getters.getSessionUser);
if (to.matched.some(record => record.meta.authRequired) && !store.getters.isAuthenticated) {//!userAuth) {
next({ path: '/login'})
} else {
next();
}
});
我四处搜索,一些解决方案说在路由器中添加你的 firebase onAuthStateChanged。这确实允许路由守卫正常工作,但是重新创建了我在将该方法添加到 main.js 之前遇到的问题 - 页面闪烁并带有预登录信息。我发现其他可能性说你可以在 onAuthStateChanged 方法周围添加一个承诺并从路由器调用它。这可能行得通,但我不确定如何在 main.js 文件中使用 firebase 来实现它,该文件包裹在正在初始化的 vue 应用程序周围。
我想避免设置 cookie 或使用 localstorage 来完成这项工作,我想知道是否有某种方法可以让 firebase、vuex state 和 vue route guards 一起正常运行。
我想出了一个方法来做到这一点。登录和注销正常工作,通知在登录和注销时工作(刷新时根本不工作),用户永久登录(onAuthState 和令牌更新应处理 1 小时超时),并且页面仅在 firebase 登录完成后加载,所以没有闪烁的“登录”而不是用户名。
main.js
initializeApp(firebaseConfig);
const auth = getAuth();
let app;
auth.onAuthStateChanged(user => {
console.log('firedOnAuthStateChanged)')
store.dispatch("setUser", user).then(() => {
if (!app) {
app = new Vue({
router,
store,
vuetify,
render: h => h(App)
}).$mount('#app')
}
});
});
authentication.js(来自 store.js 的模块)
setUser({dispatch, commit}, user) {
return new Promise((resolve, reject) => {
if(user)
{
user.getIdToken().then(token => {
commit('SET_SESSION_TOKEN', token);
this._vm.$axios.get('/api/user/login',{
headers: {
'Authorization': `Bearer ${token}`
}
})
.then((response) => {
commit('SET_SESSION_USER', response.data);
resolve(response);
})
.catch(error => {
dispatch('setSnackbar', {
color: "error",
timeout: 4000,
text: 'Failed verifying token on login.'
});
reject();
});
});
}
else
{
this._vm.$axios.post('/api/user/logout').then((response) => {
commit('SET_SESSION_USER', null);
commit('SET_SESSION_TOKEN', null);
});
resolve();
}
})
}
router.js
router.beforeEach((to, from, next) => {
const auth = getAuth();
const user = auth.currentUser;
if (to.matched.some(record => record.meta.authRequired) && !user) {
next({ path: '/login'})
} else {
next();
}
});
如果您知道更有效的方法,请告诉我。