想写个简介写了又删,删了又写,实在想不出什么好的词汇了.这个topic其实对于很多前端和全栈来说涉及的不多,毕竟在一个项目中nodejs的密码加密和token的部分在你入职的时候已经有人完成了,如果一个新项目要求从0开始或者想扩展下实践的技术栈不妨来了解下.
0.准备工作
- Nodejs既然是Nodejs作为后端,首先我们要有一个nodejs的环境.推荐>=18.
- Ejs.做nodejs的都了解,nodejs模版引擎
-
nodemon:让nodejs service持久化
-
express不多说了
-
还有其他一些插件后续用到再做说明
1.Express替换模版引擎
传统方法直接新建文件
mkdir myapp
cd muapp
npm init
来点不一样的,使用express generator来一步搞定
mkdir myapp
cd myapp
npx express-generator
看下目录结构
不错,继续 npm i 创建node_moduls初始化我们的express项目.执行npm run start or yarn start
看下效果,虽然大多数时候我们用不到UI界面,但是开发和测试的时候还是得有个界面方便我们调试开发这比纯后端的摸黑开发好很多.
习惯了手动配置端口的可能有点陌生,端口在哪?bin->www
很多express的servic已经启动.
更改模版引擎.
默认的是jade模版,但是看上去很难接受,这里换成对vue,jsp开发都好理解的ejs.
npm i ejs -D
修改引用引擎.在app.js中替换
app.set('view engine', 'jade') =>
app.set('view engine', 'ejs')
修改package.json 添加nodemon启动规则,不用每次修改都重新re-strart service的繁琐操作
"dev": "nodemon ./bin/www"
修改index.jade => index.ejs,别忘也把error.ejs顺手改了
<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
</head>
<body >
<div>Hello Evan <%= title %></div>
</body>
看下效果,舒服了
2. 密码加密
使用的bcryptjs 插件,为什么用这个.好处也是它的劣势,加密后不可逆,加密后没办法再转明文创建一个加密方法
const bcrypt = require('bcryptjs');
const hashLen = 10
const hashPassword = (pwd) => {
return bcrypt.hashSync(pwd, hashLen)
}
const comparePassword = (pwd, hash) =>{
return bcrypt.compareSync(pwd, hash, (err, isMatch) => isMatch)
}
module.exports = {
hashPassword,
comparePassword,
}
haslen: 密码后的秘文长度
hashPassword: 新用户注册的时候为其加密密码
comparePassword:当前端发送秘文时候与db中存储的秘文比较验证是否可以登录,或者权重.
3.生成token
npm i jsonwebtoken
genterator token方法
const jwt = require('jsonwebtoken');
const secret = ('../keys/secret')
const createToken = (data, time) => {
return jwt.sign(data, secret, {expiresIn: time})
}
需求在创建一个解密的密文文件 (keys/secret) 如果别人知道这个解密的密钥token就十分不安全了,很推荐用代理服务做获取
const secretKey = `adahksldss is hsd ^^ !@123`
module.exports = secretKey
在来一个验证token的合法性的函数
const verifyToken = (token) => {
try {
return jwt.verify(token, secret);
} catch (e) {
console.log(e);
return false;
}
}
很简单的代码全部完成.
创建新的路由登录加密
在app.js中
app.use('/login',login)
在router中创建login.js
const express = require('express');
const router = express.Router();
const db = require('../db/db');
const {hashPassword, comparePassword} = require('../keys/valition')
创建新用户,并加密密码
const addUserSql = `INSERT INTO users values ( ?, ?, ? ,? ,?, ?)`;
db.insert(addUserSql, [null,new Date(), acc,null, 0, await hashPassword(psd)], function(data, err) {
if (data != "1") {
console.log(`create new user: ${acc} successfully.`)
res.send(`create new user: ${acc} successfully.`)
} else {
res.send(err)
throw err
}
})
已注册用户登录(密码登录,没有token情况)
const s = comparePassword(psd.toString(), data[0]['pwd'].toString())
if (s) {
const token = createToken({username:acc}, '1h');
// res.header('Authorization', `Bearer ${token}`)
res.setHeader('Access-Control-Expose-Headers', 'Authorization');
res.header('Authorization', `Bearer ${token}`)
res.send({
statecode: `success`,
stateMessage: `username: ${acc} login successful`,
userInfo: {
role:data[0]['content'],
roleLevel: data[0]['level'],
lastloginTime: data[0]['lastlogindate'],
}
})
await markLoginTime(acc)
} else {
res.send({
statecode: `error`,
stateMessage: `username or password not correct`
})
}
使用token验证只需要函数替换成我们上面提到的验证token的函数就可以
const s = comparePassword(psd.toString(), data[0]['pwd'].toString())
=>
const s = verifyToken(token)
当然这个验证最好是写到中间件上, token的参数在头部
const validationLogin = (req, res, next) => {
const {token} = req.header;
if (verifyToken(token) ) {
// account validate success
} else {
req.body = {
...req.body,
stateBuffer: "e_403",
stateMessage: "You account not exist ."
}
}
next()
}
router.post('/validation',validationLogin ,async function(req, res) {
// xxxxx
//logic
}