使用RESTful API通過Vue處理身份驗(yàn)證
本文轉(zhuǎn)載自微信公眾號(hào)「新鈦云服」,作者李冰。轉(zhuǎn)載本文請(qǐng)聯(lián)系新鈦云服公眾號(hào)。
身份驗(yàn)證(登錄!)是許多網(wǎng)站的重要組成部分。讓我們看看如何使用Vue在網(wǎng)站上進(jìn)行處理,其方式與在任何自定義后端中進(jìn)行處理的方式相同。Vue實(shí)際上不能完全自己進(jìn)行身份驗(yàn)證,為此我們需要另一個(gè)服務(wù),因此我們將為此使用另一個(gè)服務(wù)(Firebase),然后將整個(gè)體驗(yàn)整合到Vue中。
身份驗(yàn)證在單頁(yè)應(yīng)用程序(SPA)上的工作方式與在重新加載每個(gè)頁(yè)面的站點(diǎn)上的工作方式完全不同。
我們將構(gòu)建一個(gè)用戶登錄界面,并將提交的數(shù)據(jù)發(fā)送到服務(wù)器以檢查用戶是否存在。如果是,我們將收到令牌。這非常有用,因?yàn)樗鼘⒃谖覀兊恼麄€(gè)站點(diǎn)中用于檢查用戶是否仍在登錄。如果沒有,則用戶可以隨時(shí)注冊(cè)。換句話說(shuō),它可以在許多條件上下文中使用。除此之外,如果我們需要來(lái)自服務(wù)器的任何需要登錄的信息,則令牌將通過URL發(fā)送到服務(wù)器,以便僅將信息發(fā)送給登錄的用戶。
本教程的完整演示已發(fā)布在 GitHub 上, 以供那些熟悉 閱讀代碼的人使用。我們其余的人可以繼續(xù)閱讀本文。起始文件也位于 GitHub 上, 因此您可以在我們一起編碼時(shí)繼續(xù)進(jìn)行操作。
下載后,您將npm install在終端中運(yùn)行。如果要完全自己構(gòu)建此應(yīng)用程序,則必須安裝Vuex ,Vue Router 和axios 。我們還將在該項(xiàng)目中使用Firebase ,因此花點(diǎn)時(shí)間設(shè)置一個(gè)免費(fèi)帳戶并在其中創(chuàng)建一個(gè)新項(xiàng)目。
將項(xiàng)目添加到Firebase后,轉(zhuǎn)到身份驗(yàn)證部分,并設(shè)置登錄方法,該方法將使用傳統(tǒng)的電子郵件/密碼提供程序,該方法將存儲(chǔ)在Firebase服務(wù)器上。
之后,我們將轉(zhuǎn)到Firebase Auth REST API 文檔 獲取我們的注冊(cè)并登錄API端點(diǎn)。我們需要一個(gè)API密鑰才能在我們的應(yīng)用程序中使用這些終結(jié)點(diǎn),并且可以在Firebase項(xiàng)目設(shè)置中找到它。
Firebase通過SDK提供身份驗(yàn)證,但是我們使用Auth API來(lái)演示通過任何自定義后端服務(wù)器進(jìn)行的身份驗(yàn)證。
在我們的狀態(tài)報(bào)告文件中,下面有注冊(cè)表格。由于我們專注于學(xué)習(xí)概念,因此我們?cè)谶@里使事情保持簡(jiǎn)單。
- <template>
- <div id="signup">
- <div class="signup-form">
- <form @submit.prevent="onSubmit">
- <div class="input">
- <label for="email">Mail</label>
- <input
- type="email"
- id="email"
- v-model="email">
- </div>
- <div class="input">
- <label for="name">Your Name</label>
- <input
- type="text"
- id="name"
- v-model.number="name">
- </div>
- <div class="input">
- <label for="password">Password</label>
- <input
- type="password"
- id="password"
- v-model="password">
- </div>
- <div class="submit">
- <button type="submit">Submit</button>
- </div>
- </form>
- </div>
- </div>
- </template>
如果我們不使用SPA,我們自然會(huì)使用axios將數(shù)據(jù)發(fā)送到script標(biāo)簽中,如下所示:
- axios.post('https://identitytoolkit.googleapis.com/v1/account
- s:signUp?key=[API_KEY]',{
- email:authData.email,
- password:authData.password,
- returnSecureToken:true
- })
- .then(res =>{
- console.log(res)
- })
- .catch(error => console.log(error))
- }
- }
注冊(cè)并登錄
使用SPA(在這種情況下使用Vue)與上述方法非常不同。相反,我們將在文件中的操作中使用Vuex 發(fā)送授權(quán)請(qǐng)求store.js。我們這樣做是因?yàn)槲覀兿M麄€(gè)應(yīng)用程序都知道用戶身份驗(yàn)證狀態(tài)的任何更改。
- actions:{
- signup ({commit},authData){
- axios.post('https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=[API_KEY]',{
- email:authData.email,
- password:authData.password,
- returnSecureToken:true
- })
- .then(res =>{
- console.log(res)
- router.push("/dashboard")
- })
- .catch(error => console.log(error))
- },
- login ({commit},authData){
- axios.post(https://identitytoolkit.googleapis.com/v1/accounts:signIn?key=[API_KEY]',{
- email:authData.email,
- password:authData.password,
- returnSecureToken:true
- })
- .then(res =>{
- console.log(res)
- router.push("/dashboard")
- })
- .catch(error => console.log(error))
- }
- }
我們可以對(duì)登錄方法使用幾乎相同的東西,但是可以使用登錄API端點(diǎn)代替。然后,我們將組件的注冊(cè)和登錄分派到商店中它們各自的操作。
- methods :{
- onSubmit (){
- constformData ={
- email :this.email,
- name :this.name,
- password :this.password
- }
- this.$store.dispatch('signup',formData)
- }
- }
- }
formData 包含用戶的數(shù)據(jù)。
- methods : {
- onSubmit () {
- const formData = {
- email : this.email,
- password : this.password
- }
- this.$store.dispatch('login', {email: formData.email, password: formData.password})
- }
- }
我們將接收從注冊(cè)/登錄表單中收到的身份驗(yàn)證數(shù)據(jù)(即令牌和用戶ID),并將其用作Vuex的狀態(tài)。最初的結(jié)果為null。
- state:{
- idToken:null,
- userId:null,
- user:null
- }
現(xiàn)在,我們authUser在突變中創(chuàng)建一個(gè)稱為的新方法,該方法將存儲(chǔ)從響應(yīng)中收集的數(shù)據(jù)。我們需要將路由器導(dǎo)入商店,因?yàn)樯院笮枰?/p>
- import router from'/router'
- mutations :{
- authUser (state,userData){
- state.idToken =userData.token
- state.userId =userData.userId
- }
- }
.then在我們的操作的signup / login方法中的塊內(nèi),我們將對(duì)authUser剛剛創(chuàng)建的變異的響應(yīng)提交并保存到本地存儲(chǔ)中。
- actions:{
- signup ({commit},authData){
- axios.post('https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=[API_KEY]'),{
- email:authData.email,
- password:authData.password,
- returnSecureToken:true
- })
- .then(res =>{
- console.log(res)
- commit('authUser',{
- token:res.data.idToken,
- userId:res.data.localId
- })
- localStorage.setItem('token',res.data.idToken)
- localStorage.setItem('userId',res.data.localId)
- router.push("/dashboard")
- })
- .catch(error => console.log(error))
- },
- login ({commit},authData){
- axios.post('https://identitytoolkit.googleapis.com/v1/accounts:signIn?key=[API_KEY]'),{
- email:authData.email,
- password:authData.password,
- returnSecureToken:true
- })
- .then(res =>{
- console.log(res)
- commit('authUser',{
- token:res.data.idToken,
- userId:res.data.localId
- })
- localStorage.setItem('token',res.data.idToken)
- localStorage.setItem('userId',res.data.localId)
- router.push("/dashboard")
- })
- .catch(error => console.log(error))
- }
- }
設(shè)置身份驗(yàn)證防護(hù)
現(xiàn)在我們已經(jīng)將令牌存儲(chǔ)在應(yīng)用程序中,接下來(lái)將在設(shè)置Auth Guard時(shí)使用該令牌。什么是Auth Guard?它可以保護(hù)儀表板,防止未經(jīng)身份驗(yàn)證的用戶訪問沒有令牌的儀表板。
首先,我們將進(jìn)入路線文件并導(dǎo)入商店。由于令牌將確定用戶的登錄狀態(tài),因此導(dǎo)入了商店。
- import store from'./store.js'
那么,我們的路線陣列內(nèi),去到儀表板路徑,添加方法beforeEnter這個(gè)方法有三個(gè)參數(shù):to,from和next。在這種方法中,我們只是簡(jiǎn)單地說(shuō),如果存儲(chǔ)了令牌(如果通過身份驗(yàn)證,令牌將自動(dòng)完成),那么next,意味著令牌將沿著指定的路線繼續(xù)。否則,我們會(huì)將未經(jīng)身份驗(yàn)證的用戶帶回注冊(cè)頁(yè)面。
- {
- path:'/dashboard',
- component:DashboardPage,
- beforeEnter (to,from, next){
- if(store.state.idToken){
- next()
- }
- else{
- next('/signin')
- }
- }
- }
創(chuàng)建UI狀態(tài)
此時(shí),無(wú)論是否登錄,我們?nèi)匀豢梢栽趯?dǎo)航中看到儀表板,這不是我們想要的。我們必須在調(diào)用的getters下添加另一個(gè)方法,該方法ifAuthenticated檢查狀態(tài)中的令牌是否為null,然后相應(yīng)地更新導(dǎo)航項(xiàng)。
- getters:{
- user (state){
- returnstate.user
- },
- ifAuthenticated (state){
- returnstate.idToken !==null
- }
- }
接下來(lái),讓我們打開標(biāo)題組件,并auth在computed屬性內(nèi)部創(chuàng)建一個(gè)稱為方法。這將分派給ifAuthenticated我們剛剛在商店中創(chuàng)建的吸氣劑。如果沒有令牌,ifAuthenticated將返回false,這自動(dòng)意味著auth也將是null,反之亦然。在這之后,我們添加了一個(gè)v-if檢查,如果auth是null或不是,確定儀表盤選項(xiàng)是否會(huì)顯示在導(dǎo)航。
- <template>
- <header id="header">
- <div class="logo">
- <router-link to="/">Vue Authenticate</router-link>
- </div>
- <nav>
- <ul>
- <li v-if='auth'>
- <router-link to="/dashboard">Dashboard</router-link>
- </li>
- <li v-if='!auth'>
- <router-link to="/signup">Register</router-link>
- </li>
- <li v-if='!auth'>
- <router-link to="/signin">Log In</router-link>
- </li>
- </ul>
- </nav>
- </header>
- </template>
- <script>
- exportdefault{
- computed:{
- auth (){
- returnthis.$store.getters.ifAuthenticated
- }
- },
- }
- </script>
注銷
沒有注銷按鈕的應(yīng)用程序是什么?讓我們創(chuàng)建一個(gè)名為的新突變clearAuth,它將令牌和都設(shè)置userId為null。
- mutations:{
- authUser (state,userData){
- state.idToken =userData.token
- state.userId =userData.userId
- },
- clearAuth (state){
- state.idToken =null
- state.userId =null
- }
- }
然后,在我們的logout操作中,我們承諾clearAuth,刪除本地存儲(chǔ)并添加router.replace('/')以在注銷后正確地重定向用戶。
返回標(biāo)題組件。我們有一種onLogout方法可以logout在商店中調(diào)度我們的行動(dòng)。然后,我們@click在按鈕中添加一個(gè),該按鈕將調(diào)用onLogout方法,如下所示:
- <template>
- <header id="header">
- <div class="logo">
- <router-link to="/">Vue Authenticate</router-link>
- </div>
- <nav>
- <ul>
- <li v-if='auth'>
- <router-link to="/dashboard">Dashboard</router-link>
- </li>
- <li v-if='!auth'>
- <router-link to="/signup">Register</router-link>
- </li>
- <li v-if='!auth'>
- <router-link to="/signin">Log In</router-link>
- </li>
- <li v-if='auth'>
- <ul @click="onLogout">Log Out</ul>
- </li>
- </ul>
- </nav>
- </header>
- </template>
- <script>
- exportdefault{
- computed:{
- auth (){
- returnthis.$store.getters.ifAuthenticated
- }
- },
- methods:{
- onLogout(){
- this.$store.dispatch('logout')
- }
- }
- }
- </script>
自動(dòng)登錄?當(dāng)然!
我們的應(yīng)用程序差不多完成了。我們可以使用剛剛完成的所有UI更改進(jìn)行注冊(cè),登錄和注銷。但是,當(dāng)我們刷新應(yīng)用程序時(shí),我們會(huì)丟失數(shù)據(jù)并注銷,必須重新開始,因?yàn)槲覀儗⒘钆坪虸D存儲(chǔ)在JavaScript的Vuex中。這意味著刷新后,應(yīng)用程序中的所有內(nèi)容都會(huì)重新加載到瀏覽器中。
我們要做的是在本地存儲(chǔ)中檢索令牌。這樣,無(wú)論何時(shí)刷新窗口,我們都可以在瀏覽器中擁有用戶的令牌,只要令牌仍然有效,甚至可以自動(dòng)登錄用戶。
創(chuàng)建一個(gè)名為的新動(dòng)作方法,僅當(dāng)用戶擁有AutoLogin令牌時(shí),我們才能userId從本地存儲(chǔ)中獲取令牌。然后,我們將數(shù)據(jù)提交給authUser突變中的方法。
- actions :{
- AutoLogin ({commit}){
- const token =localStorage.getItem('token')
- if(!token){
- return
- }
- constuserId =localStorage.getItem('userId')
- const token =localStorage.getItem('token')
- commit('authUser',{
- idToken: token,
- userId:userId
- })
- }
然后,我們轉(zhuǎn)到我們App.vue的created方法,并在autoLogin加載應(yīng)用程序時(shí)從商店中分發(fā)。
- created (){
- this.$store.dispatch('AutoLogin')
- }
好極了!這樣,我們就可以在應(yīng)用程序內(nèi)成功實(shí)現(xiàn)身份驗(yàn)證,現(xiàn)在可以使用進(jìn)行部署npm run build。觀看現(xiàn)場(chǎng)演示 以觀看實(shí)際操作。
原文: https://css-tricks.com/tackling-authentication-with-vue-using-restful-apis/