今天會做兩個API
開啟後端(b2e)專案開始吧~
帳戶清單可以放在前端的頭像Menu中,已登入的就呈現在最上方,其餘未登入的就呈現在中間區塊,如圖碼掉的部分xD
開啟 /routes/users/index.js 新增路由:
router.get('/signintokens', userCtrl.userCtrlSigninTokens);
路徑 signintokens 對應controller: userCtrlSigninTokens
註: 注意這裡用的是GET方法!!
開啟 /controllers/users.controller.js 加上 controller: userCtrlSigninTokens
const userCtrlSigninTokens = (req, res) => {
userModule.userModuleSigninTokens(req.signedCookies.SigninTokens).then((moduleResult) => {
res.send(Object.assign({ success: true }, moduleResult));
}).catch((error) => {
res.send(Object.assign({ success: false }, error));
});
};
開啟 /modules/users.module.js
判斷Token是否存在,不存在就回傳「尚未登入」:
const userModuleSigninTokens = (signinTokens) => {
return new Promise((resolve, reject) => {
if (signinTokens) {
...
} else {
reject({ message: "尚未登入" });
}
});
};
Token存在則逐筆解密,解密後回傳其中的帳號和姓名及啟用狀態:
let users = signinTokens.map(function (item) {
let user;
jwt.verify(item.token, config.jwt.tokensecret, (error, decoded) => {
if (error) {
reject({ message: error });
} else {
user = {
accountId: decoded.accountId,
username: decoded.username,
active: item.active,
};
}
});
return user;
});
resolve({ users });
用到了陣列的
map
方法,作用是將陣列內容逐筆跑並且回傳想要的結果
寫到這邊我發現 jwt.verify
jwt解密方法在module裡面用了好多次...
為了簡化程式碼及可維護性,把它額外拉出去寫了一支function:
function jwtDecode(token, func) {
jwt.verify(token, config.jwt.tokensecret, (error, decoded) => {
if (error) {
reject({ message: error });
} else {
func(decoded);
}
});
}
傳入變數:
原本的解密部分就可以改寫為:
jwtDecode(item.token, (decoded) => {
user = {
accountId: decoded.accountId,
username: decoded.username,
active: item.active,
};
});
前面有用到 jwt.verify
的程式碼都可以一併改寫!!
日後只要改這支function就好,不用每個 jwt.verify
都改一次,增加可維護性
到這邊帳戶清單API就完成囉~
我登入了第2個帳號,可以參考POSTMAN呼叫的結果:
移除帳戶API路徑會和帳戶清單API的路徑相同,不過方法變為 PUT
並且後方帶參數來判斷要移除的帳號
一樣開啟 /routes/users/index.js 新增路由:
router.put('/signintokens/:accountId', userCtrl.userCtrlSigninTokens);
路徑 signintokens 及帳號參數 :accountId 對應controller: userCtrlSigninTokens
註: 注意這裡用的是PUT方法喔!!
開啟 /controllers/users.controller.js
因為用到同一支controller,所以controller裡面會先判斷是用什麼方法進來的
(有其他解法的話歡迎提供我會很感謝xD)
const userCtrlSigninTokens = (req, res) => {
switch (req.method) {
case 'GET':
...
break;
case 'PUT':
...
break;
}
};
PUT 內容會傳入Token和要移除的帳號給module處理,module回覆處理結果後簽回cookie:
userModule.userModuleRemoveSigninToken(req.signedCookies.SigninTokens, req.params.accountId)
.then((moduleResult) => {
res.cookie('SigninTokens', moduleResult, { signed: true });
res.send({ success: true });
})
.catch((error) => {
res.send(Object.assign({ success: false }, error));
});
開啟 /modules/users.module.js 判斷Token是否存在,不存在就回傳「尚未登入」:
const userModuleRemoveSigninToken = (signinTokens, accountId) => {
return new Promise((resolve, reject) => {
if (signinTokens) {
...
} else {
reject({ message: "尚未登入" });
}
});
};
再加一層判斷帳號有沒有傳進來,沒有就回傳「帳戶不符規定」:
if (signinTokens) {
if (accountId) {
...
} else {
reject({ message: "帳戶不符規定" });
}
} else {
reject({ message: "尚未登入" });
}
接著會用到陣列的 findIndex
方法找到對應帳號的索引值
findIndex
作用是搜尋陣列中符合指定條件的項目索引值
let signinTokensIndex = signinTokens.findIndex(function (item) {
let decodedAccountId;
jwtDecode(item.token, (decoded) => {
decodedAccountId = decoded.accountId
});
return decodedAccountId === accountId;
});
有索引值後就知道要移除的帳號是第幾筆,再使用陣列的 splice
方法來移除並回傳,找不到索引值就回傳「無此帳號」
splice
作用是移除陣列中指定的索引項目 第2個參數是要移除的筆數
if (signinTokensIndex > -1) {
signinTokens.splice(signinTokensIndex, 1);
resolve(signinTokens);
} else {
reject({ message: "無此帳號" });
}
到這邊移除帳戶API就完成囉~
來看看效果吧~原本清單有兩筆,移除其中一筆再抓一次清單就剩下一筆:
今日重點:
有需要改進或是任何意見建議歡迎下面留言~