目前已經登入成功,那就先來將登入狀態處理一下,以及登出的功能。
在 typedefs.ts 檔案,先加上以下的 checkJWT 那行:
type Mutation {
insertUser(nickname: String!, email: String!, password: String): User!
updateUser(id: Int!, firstname: String!, lastname: String!): User!
deleteUser(id: Int!): Boolean!
authUser(username: String!, password: String!): String!
checkJWT(jwt: String!): Boolean!
}
然後在 resolvers.ts,原來的:
export const resolvers = {
Query: {
hello: () => `Hello World!`,
allUsers: () => allUsers()
},
Mutation: {
insertUser: (_: any, args: any) => insertUser(args),
updateUser: (_: any, args: any) => updateUser(args),
deleteUser: (_: any, args: any) => deleteUser(args),
authUser: (_: any, args: any) => authUser(args),
}
};
改成(一樣僅加上 checkJWT 那行):
export const resolvers = {
Query: {
hello: () => `Hello World!`,
allUsers: () => allUsers()
},
Mutation: {
insertUser: (_: any, args: any) => insertUser(args),
updateUser: (_: any, args: any) => updateUser(args),
deleteUser: (_: any, args: any) => deleteUser(args),
authUser: (_: any, args: any) => authUser(args),
checkJWT: (_: any, args: any) => checkJWT(args)
}
};
然後實作一下 checkJWT 函式,加以下的程式碼即可:
async function checkJWT(args){
const payload = await verify(args.jwt, key);
if(payload){
return true;
}
return false;
}
經由以上的實作,其實就是會判斷由 Web APP 傳過來的 JWT 是否驗證通過,如果通過,就回傳 true,不通過的話就回傳 false。
登入的狀態,是不管在哪個頁面,重新整理頁面時,通常都會需要去判斷的,所以這部份,寫在 App.vue 檔案中。
在 App.vue 的 script 標籤當中,加以下的原始碼:
這段原始碼,其實就是將 jwt 傳送給後端,然後驗證該 jwt 是不是仍有效,如果通過,那麼 loginStatus 就設定 true;反之則為 false。
export default {
data(){
return {
loginStatus: false
};
},
created(){
let jwt = localStorage.getItem("jwt");
if(jwt){
fetch("http://localhost:8080/graphql", {
method: 'POST',
body: JSON.stringify({
query: `mutation {
checkJWT(jwt: "${jwt}")
}`
})
}).then(res => res.json()).then(body => {
if(body.data.checkJWT){
this.loginStatus = true;
}else{
this.loginStatus = false;
}
});
}
}
}
然後,在 template 標籤當中,以下這行:
component(:is="Component" :key="$route.path")
改成:
component(:is="Component" :key="$route.path" :login-status="loginStatus")
也就是透過 props 的概念,將 loginStatus 資料,往子元件去傳遞。
先將 src/views/Home.vue 檔案當中,以下這行移除:
router-link(:to="{name: 'WebBuild'}" style="color: white;") 進到建立網頁的後台(使用 router-link)
然後在 src/views/Home.vue 檔案當中,加以下 props 設定,用來承接從父層元件傳遞過來的屬性:
export default {
props: ["loginStatus"], // 加這行
// 以下這邊是其它程式
}
而在 template 標籤當中呢,原來的表單,改成以下:
這段程式呢,留意 v-if 和 v-else 的部份,也就是用來判斷目前登入的狀態是什麼(已登入或未登入),然後顯示對應的介面。
div.login_block(v-if="loginStatus")
router-link(:to="{name: 'WebBuild'}" class="web_build") 後台建立網頁
button(type="button" @click="signout") 登出
form(v-else action="#" method="#" class="login_form")
div.input_group
label 帳號
input(type="text" autocomplete="username" v-model="email")
div.input_group
label 密碼
input(type="password" autocomplete="current-password" v-model="password")
div.input_group
label
button(type="button" @click="auth_user") 登入
router-link(:to="{name: 'register'}" class="register") 還不是會員嗎?請先註冊成為會員
然後在 style 標籤中,新增以下的 css:
div.login_block
a.web_build
color: white
font-size: 1.8rem
background-image: radial-gradient(100% 100% at 100% 0, rgba(0,172,193,1) 0, #4e5aba 100%)
border: 0
border-radius: 6px
box-shadow: rgba(45, 35, 66, .4) 0 2px 4px,rgba(45, 35, 66, .3) 0 7px 13px -3px,rgba(58, 65, 111, .5) 0 -3px 0 inset
color: #fff
display: inline-block
height: 48px
line-height: 48px
padding-left: 16px
padding-right: 16px
text-decoration: none
&:focus
box-shadow: #3c4fe0 0 0 0 1.5px inset, rgba(45, 35, 66, .4) 0 2px 4px, rgba(45, 35, 66, .3) 0 7px 13px -3px, #3c4fe0 0 -3px 0 inset
&:hover
box-shadow: rgba(45, 35, 66, .4) 0 4px 8px, rgba(45, 35, 66, .3) 0 7px 13px -3px, #3c4fe0 0 -3px 0 inset
transform: translateY(-2px)
&:active
box-shadow: #3c4fe0 0 3px 7px inset
transform: translateY(2px)
將以上的程式修改完成後,就可以在首頁的登入部份,實際測試看看,登入成功的話,首頁的頁面會重新整理,就會看到如下圖:
右側有兩個按鈕,左邊那個按鈕,點下去就是會進到未來要做的頁面(之前有建立過);右邊的按鈕呢,就是登出按鈕。
在 src/views/Home.vue 當中,在 methods 屬性當中,加一個函式叫做 signout 函式,如下,以下列出 methods 的部份:
methods: {
auth_user(){
// 這裡有其它程式碼
},
signout(){ // 加這個函式
localStorage.removeItem("jwt");
alert("登出成功");
location.reload();
}
}
所以登出功能很簡單,就是將 localStorage 中的 jwt 資料給移除即可。登出後,頁面會重新整理,就會出現如下圖(未登入的介面):
目前首頁可以區分 已登入狀態、未登入狀態 了,其實有用 Vue 當中的 provide/injdect 的部份,但有個地方怪怪的,所以還是先用 props 的方式將資料往內層元件做傳遞,也是ok的。