[英]Why is firebase authentication not persisting on refresh in Ionic with Vue and Pinia?
[英]Storing Firebase accessToken in Pinia store - Vue3
我是 Vue 的新手,这是我第一次使用 Pinia。 我正在按照本指南设置 Firebase、Pinia 和 Axios。我正在构建的应用程序使用 FirebaseUI 通过 email 链接让用户登录 - 这一切都发生在下面的 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>
当用户成功登录时,应用程序更新 Pinia 商店用户 object,AuthResult 从signInSuccessWithAuthResult
function返回 object。调试器时,我可以看到存储的 object 如下所示:
{
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
时,它已经消失了。 用户 object 的大部分(如果不是全部)其他属性仍然存在,但访问令牌不存在,因此我很确定我正在正确使用商店:
{
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);
第二 - userStore
用户商店负责跑腿工作。 当我们想从我们的 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();
});
},
},
});
*** step3 在 vue 中设置登录/注册组件。 ***
<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() 方法并以与登录/注册视图中的设置相同的方式访问它
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.