在Pinia商店存储Firebase accessToken-Vue3



我对Vue相当陌生,这是我第一次使用Pinia。我按照本指南设置Firebase、Pinia和Axios。我正在构建的应用程序使用FirebaseUI通过电子邮件链接让用户登录-这一切都发生在下面的LoginPage组件中:

(请忽略所有类型不正确的变量/函数-我只是想首先让它发挥作用(

<script setup lang="ts">
import { onMounted } from "vue";
import { EmailAuthProvider } from "firebase/auth";
import { auth } from "firebaseui";
import { auth as firebaseAuth } from "../firebase/config";
import { useUserStore } from "../stores/user"
onMounted(async () => {
const uiConfig: auth.Config = {
signInSuccessUrl: "/",
signInOptions: [
{
provider: EmailAuthProvider.PROVIDER_ID,
signInMethod: EmailAuthProvider.EMAIL_LINK_SIGN_IN_METHOD,
forceSameDevice: true,
},
],
callbacks: {
signInSuccessWithAuthResult: function (authResult) {
const store = useUserStore();
store.user = authResult;
return true;
},
},
};
const ui = new auth.AuthUI(firebaseAuth);
ui.start("#firebaseui-auth-container", uiConfig);
});
</script>
<template>
<div id="firebaseui-auth-container"></div>
</template>

当用户成功登录时,应用程序会使用signInSuccessWithAuthResult函数的AuthResult返回对象更新Pinia商店用户对象。当调试器时,我可以看到存储的对象如下所示:

{
additionalUserInfo: {...}
operationType: "signIn"
user: {
accessToken: "eyJhbGciOiJSUzI1N..."
auth: {...}
displayName: null
...
}
}

accessToken正在被存储。用户存储如下:

import { defineStore } from 'pinia'
export const useUserStore = defineStore("userStore", {
state: () => ({
user: null as any
}),
getters: {
getUser(state) {
return state.user
}
}
})

在应用程序中,我设置了一个axios拦截器,它将accessToken附加到应用程序发出的任何axios请求:

axiosInstance.interceptors.request.use((config) => {
const userStore = useUserStore();

if (userStore) {
debugger;
// accessToken is undefined
config.headers.Authorization = 'Bearer ' + userStore.user.user.accessToken;
}
return config;
});

此时,当尝试从用户存储中检索accessToken时,它已经不存在了。用户对象中的大多数(如果不是全部的话(其他属性仍然存在,但访问令牌不存在,因此我非常确信我正确地使用了存储:

{
additionalUserInfo: {...}
credential: null
operationType: "signIn"
user: {
// accessToken is gone
apiKey: "..."
appName: "[DEFAULT]"
email: "..."
emailVerified: true
....
}
}

有人能解释一下我哪里出了问题吗?为什么accessToken要从商店里撤下?在我看来,我似乎正确地使用了Pinia存储,而且我非常确信拦截器也是正确的。然而,我可能会以错误的方式存储访问令牌。如果您能提供有关如何使用Vue正确设置Firebase身份验证的任何帮助/建议,我将不胜感激。

编辑为在拦截器内部调试时包含用户存储的值

看起来accessToken可能在userStore.user.user.accessToken中?

我刚刚结束了你所处的同一场战斗…IMO有很多方法可以配置此设置。。。这类似于为什么您可能在一个地方使用回调,而在另一个地方则使用异步等待——这取决于您的项目结构。

这里有一个简单的例子可以帮助你澄清它

首先创建一个firebase文件来保存配置。将其放在您的组织习惯告诉您放的地方。只需记住,以便我们稍后使用。

import { initializeApp } from "firebase/app";
import { getAuth } from "firebase/auth";
const firebaseConfig = {
apiKey: "",
authDomain: "",
projectId: "",
storageBucket: "",
messagingSenderId: "",
appId: "",
measurementId: "",
};
// Initialize Firebase
const app = initializeApp(firebaseConfig);
//initialize firebase auth
export const auth = getAuth(app);

第二个用户存储

用户商店负责跑腿。当我们想从ui中与userauth交互时,我们将使用这些操作。

import {
createUserWithEmailAndPassword,
onAuthStateChanged,
signInWithEmailAndPassword,
signOut,
} from "firebase/auth";
import { auth } from "../firebase"; // the file we made above
import router from "../router";
export const useUserStore = defineStore("userStore", {
state: () => ({
userData: null,
loadingUser: false,
loadingSession: false,
}),
actions: {
async registerUser(email, password) {
this.loadingUser = true;
try {
const { user } = await createUserWithEmailAndPassword(
auth,
email,
password
);
this.userData = { email: user.email, uid: user.uid };
router.push("/");
} catch (error) {
console.log(error);
} finally {
this.loadingUser = false;
}
},
async loginUser(email, password) {
this.loadingUser = true;
try {
const { user } = await signInWithEmailAndPassword(
auth,
email,
password
);
this.userData = { email: user.email, uid: user.uid };
router.push("/");
} catch (error) {
console.log(error);
} finally {
this.loadingUser = false;
}
},
async logOutUser() {
try {
await signOut(auth);
this.userData = null;
router.push("/login");
} catch (error) {
console.log(error);
}
},
currentUser() {
return new Promise((resolve, reject) => {
const unsuscribe = onAuthStateChanged(
auth,
(user) => {
if (user) {
this.userData = { email: user.email, password: user.password };
} else {
this.userData = null;
}
resolve(user);
},
(e) => reject(e)
);
unsuscribe();
});
},
},
});

***步骤3在vue中设置login/reg组件。***

<div>
<form @submit.prevent="login">
<label>
Email:
<input type="email" v-model="email" required />
</label>
<br />
<label>
Password:
<input type="password" v-model="password" required />
</label>
<br />
<button type="submit">Login</button>
</form>
</div>
</template>
<script>
import { useUserStore } from "../stores/user";
export default {
data() {
return {
email: "",
password: "",
};
},
methods: {
async login() {
try {
await this.userStore.loginUser(this.email, this.password);  // 
} catch (error) {
console.error(error);
}
},
},
// because of below setup you can access this.userStore() singleton 
setup() {  
const userStore = useUserStore();
return {
userStore,
};
},
};
</script>

寄存器将是simailar

<div>
<form @submit.prevent="register">
<label>
Email:
<input type="email" v-model="email" required />
</label>
<br />
<label>
Password:
<input type="password" v-model="password" required />
</label>
<br />
<button type="submit">Register</button>
</form>
</div>
</template>
<script>
import { useUserStore } from "../stores/user";
export default {
data() {
return {
email: "",
password: "",
};
},
methods: {
async register() {
try {
await this.userStore.registerUser(this.email, this.password);
} catch (error) {
console.error(error);
}
},
},
setup() {
const userStore = useUserStore();
return {
userStore,
};
},
};
</script>

现在,每当你想访问用户时,它都在userStore.userData 中

如果你还没有userStore,只需使用useUserStore((方法,并以与登录/注册视图中的设置相同的方式访问它

最新更新