node腳手架搭建服務(wù)器實(shí)現(xiàn)token驗(yàn)證的方法
內(nèi)容
- 用腳手架快速搭建 node 項(xiàng)目
- 用 mysql 連接池實(shí)現(xiàn)與數(shù)據(jù)庫(kù)的交互
- 用 jsonwebtoken 實(shí)現(xiàn) token 身份驗(yàn)證
- 綜合案例:用簡(jiǎn)介登錄頁(yè)面實(shí)現(xiàn)上述內(nèi)容
1. 快速搭建 node 項(xiàng)目
我們都知道 express 框架可高效的開(kāi)發(fā) node 服務(wù)器,但對(duì)于底層的搭建還要靠自己手寫(xiě)。然而 express-generator 的出現(xiàn)就很好地解決了此問(wèn)題,它可一鍵為我們生成項(xiàng)目基本骨架,可謂node 腳手架
1.1 生成項(xiàng)目
①:首先全局安裝 express : npm install express -g
②:接著全局安裝 express-generator:npm install express-generator -g
③:然后使用命令創(chuàng)建項(xiàng)目: express token_learn(項(xiàng)目名稱(chēng))
1.2 修改入口文件
對(duì)于好多習(xí)慣了手?jǐn)]服務(wù)器的人,app.js 總是讓人難忘,奈何此骨架中入口文件為 www.js。此時(shí)我們可以手動(dòng)修改app.js 代碼,讓其成為我們的入口文件
示例:
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
const index = require('./routes/index');
const users = require('./routes/users');
const app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', index);
app.use('/users', users);
app.listen(3000, () => console.log('server is run 3000'))
2. 連接mysql 數(shù)據(jù)庫(kù)
此處采用連接池的方式進(jìn)行連接(高效安全)
2.1 創(chuàng)建連接
①:安裝 mysql 模塊:npm i mysql
②:在項(xiàng)目根目錄下配置連接池
首先在項(xiàng)目根目錄下創(chuàng)建 util 文件夾,文件夾下創(chuàng)建 bdconfig.js 文件
bdconfig.js
const mysql = require('mysql');
module.exports = {
mysqlParams: {
host: 'localhost', //域名
port: '3306', //端口
user: 'root', //用戶(hù)名
password: 'myroot', //密碼
database: 'nodeapi' //數(shù)據(jù)庫(kù)
},
sySqlConnect(sql, sqlArr) {
return new Promise((resolve, reject) => { //用Promise對(duì)象將其改造,方便接收數(shù)據(jù)
const pool = mysql.createPool(this.mysqlParams);
pool.getConnection((err, conn) => {
if (err) {
reject(err)
} else {
conn.query(sql, sqlArr, (err, data) => { //操作數(shù)據(jù)庫(kù)
if (err) {
reject(err)
} else {
resolve(data)
}
})
conn.release() //釋放連接
}
})
})
}
}
2.2 使用連接
使用時(shí)只需要傳入 sql(sql語(yǔ)句)、sqlArr(參數(shù)),通過(guò)Promise 改造后可直接用返回值拿到結(jié)果
3. token 身份驗(yàn)證
隨著web 的發(fā)展,session、cookie 的驗(yàn)證方式弊端也愈發(fā)突出,此時(shí)token孕育而生,token的強(qiáng)大不僅限于其是無(wú)狀態(tài)的,還在于它可以跨域
3.1 實(shí)現(xiàn)步驟
①:首先安裝 jsonwebtoken 模塊:npm i jsonwebtoken
②:接著在項(xiàng)目中使用該模塊
const dbConfig = require('../util/dbconfig');
const jwt = require('jsonwebtoken');
const secret = 'login-rule'; //秘鑰規(guī)則(自定義)
token = async(req, res, next) => { //定義token驗(yàn)證中間件函數(shù)(應(yīng)用于除登錄外的每個(gè)請(qǐng)求)
if (req.headers.authorization) {
const token = req.headers.authorization;
const { id, username } = jwt.verify(token, secret); // 對(duì)token進(jìn)行解密查找
let sql = 'select * from test where id=?';
let sqlArr = [id];
let result = await dbConfig.sySqlConnect(sql, sqlArr);
if (result.length === 0) {
res.status(200).send({ msg: '用戶(hù)錯(cuò)誤' })
return
}
if (username !== result[0].username) {
res.status(200).send({ msg: '用戶(hù)錯(cuò)誤' })
} else {
next()
}
} else {
res.status(200).send({ msg: '無(wú)效請(qǐng)求頭' })
}
}
login = async(req, res) => { //定義登錄接口(因?yàn)檫@個(gè)請(qǐng)求頭不攜帶token,所以引用在token驗(yàn)證中間件之前)
let { username, password } = req.body;
let sql = 'select * from test where username=?';
let sqlArr = [username];
let result = await dbConfig.sySqlConnect(sql, sqlArr);
if (result.length) {
if (password === result[0].password) {
const { id, username } = result[0];
//對(duì)token進(jìn)行加密響應(yīng)個(gè)客戶(hù)端(參數(shù)1:傳值規(guī)則;參數(shù)2:加密規(guī)則; 參數(shù)3:定義時(shí)間)
const token = jwt.sign({ id, username }, secret, { expiresIn: 60 * 60 });
res.status(200).send({ msg: '登陸成功', token: token, status: 200 });
} else {
res.status(200).send({ msg: '登陸失敗', status: 422 });
}
} else {
res.status(200).send({ msg: '用戶(hù)名不存在', status: 401 })
}
}
// 驗(yàn)證身份中間件
module.exports = {
token,
login
}
③:在 app.js 中進(jìn)行配置
// 寫(xiě)在 app.use() 之后,路由之前
app.use('/users/loginjwt', token.login); //登錄接口(無(wú)需驗(yàn)證token,所以寫(xiě)在token中間件之前)
app.use(token.token);
4. 案例實(shí)現(xiàn) token
4.1 原理闡述
為確保身份唯一且有效:用戶(hù)每次發(fā)送登錄請(qǐng)求且登錄成功,服務(wù)器端都會(huì)響應(yīng)給用戶(hù)一個(gè)含用戶(hù)信息(唯一)的加密 token(字符串),此時(shí)用戶(hù)接收到 token,并把 token 存儲(chǔ)在 sessionStorage 或 localStorage中(此處為)。同時(shí)用戶(hù)每次發(fā)送其他請(qǐng)求時(shí),在請(qǐng)求頭中攜帶本地的 token,服務(wù)器端 token驗(yàn)證中間件攔截請(qǐng)求,對(duì) token進(jìn)行解密,得到用戶(hù)信息并與數(shù)據(jù)庫(kù)比對(duì),信息存在則放行(身份驗(yàn)證成功)。
4.2 效果預(yù)覽

4.3 開(kāi)始實(shí)現(xiàn)
寫(xiě)簡(jiǎn)潔靜態(tài)頁(yè)面,且實(shí)現(xiàn)ajax 請(qǐng)求
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="../javascripts/jquery.min.js"></script>
<title>Document</title>
</head>
<body>
<form id="loginform">
<input type="text" name="username">
<input type="password" name="password">
<input type="submit" value="登錄">
</form>
<script>
$(function() {
$('#loginform').on('submit', function() {
const formdata = $(this).serialize()
$.ajax({
url: '/users/loginjwt',
type: 'post',
data: formdata,
success(res) {
if (res.status === 200) {
window.sessionStorage.setItem('token', res.token);
location.href = '/user/index.html'
}
}
})
return false
})
})
</script>
</body>
</html>
index.html
<script>
if (!sessionStorage.getItem('token')) {
location.href = '/user/login.html'
}
</script>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="../javascripts/jquery.min.js"></script>
<title>Document</title>
</head>
<body>
<h1>welcome index</h1>
<a href="javascript:;" rel="external nofollow" >退出登錄</a>
<script>
$(function() {
$.ajaxSetup({
// 發(fā)送請(qǐng)求前觸發(fā)
beforeSend(xhr) {
// 在此設(shè)置自定義請(qǐng)求頭
xhr.setRequestHeader('authorization', sessionStorage.getItem('token'))
}
})
$.ajax({
url: '/users',
success(res) {
console.log(res);
}
})
$('a').on('click', function() {
sessionStorage.clear();
location.href = '/user/login.html'
})
})
</script>
</body>
</html>
4.4 注意點(diǎn)
值得注意的是,對(duì)于 本地 token 的驗(yàn)證(是否存在)一定要寫(xiě)在頁(yè)面最頂端(防止頁(yè)面加載,再次發(fā)送用戶(hù)列表請(qǐng)求)
對(duì)于 ajax請(qǐng)求頭,一個(gè)一個(gè)加真的很煩,此處用 $ajaxSetup方法,修改ajax 的默認(rèn)配置 。配置過(guò)后,寫(xiě)在其下邊的 ajax 請(qǐng)求,都會(huì)帶上請(qǐng)求頭。
到此這篇關(guān)于node腳手架搭建服務(wù)器實(shí)現(xiàn)token驗(yàn)證的方法的文章就介紹到這了,更多相關(guān)node token驗(yàn)證 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Nodejs alpine基礎(chǔ)之docker鏡像構(gòu)建
這篇文章主要為大家介紹了Nodejs alpine基礎(chǔ)之docker鏡像構(gòu)建,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07
詳解nodejs微信公眾號(hào)開(kāi)發(fā)——5.素材管理接口
這篇文章主要介紹了詳解nodejs微信公眾號(hào)開(kāi)發(fā)——5.素材管理接口,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2017-04-04
Node.js基于node-schedule實(shí)現(xiàn)定時(shí)任務(wù)的操作步驟
實(shí)際工作中,可能會(huì)遇到定時(shí)清除某個(gè)文件夾內(nèi)容,定時(shí)發(fā)送消息或發(fā)送郵件給指定用戶(hù),定時(shí)導(dǎo)出某些數(shù)據(jù)等,node-schedule是一個(gè)非常不錯(cuò)的npm包,可以幫助我們快速的創(chuàng)建和管理定時(shí)任務(wù),所以本文介紹了Node.js基于node-schedule實(shí)現(xiàn)定時(shí)任務(wù)的操作步驟,需要的朋友可以參考下2024-09-09
nodejs個(gè)人博客開(kāi)發(fā)第七步?后臺(tái)登陸
這篇文章主要為大家詳細(xì)介紹了nodejs個(gè)人博客開(kāi)發(fā)的后臺(tái)登陸功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-04-04
windows實(shí)現(xiàn)npm和cnpm安裝步驟
這篇文章主要介紹了windows實(shí)現(xiàn)npm和cnpm安裝步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-10-10
Express服務(wù)器端代碼熱加載的實(shí)現(xiàn)代碼
這篇文章主要介紹了Express服務(wù)器端代碼熱加載的實(shí)現(xiàn),文中通過(guò)代碼示例給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2024-01-01
詳解express + mock讓前后臺(tái)并行開(kāi)發(fā)
這篇文章主要介紹了詳解express + mock讓前后臺(tái)并行開(kāi)發(fā),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-06-06

