bcrypt密码加密
在实际应用中,直接将用户密码以明文信息进行存储是不安全的做法,这里讲解一下如何使用密码解析与解析
- 安装bcrypt模块
yarn add bcrypt
- 加密与解析函数
这里需要自己进行promise的封装,才能避免因为异步的原因导致出错
exports.hash = (myPlaintextPassword) => {
return new Promise((resolve, reject) => {
//第二个参数是盐
bcrypt.hash(myPlaintextPassword, 10, function (err, hash) {
if(err){
reject(err)
}else{
//成功则返回加密后的hash值
resolve(hash)
}
})
})
}
exports.compare=(myPlaintextPassword,hash)=>{
return new Promise((resolve,reject)=>{
bcrypt.compare(myPlaintextPassword,hash,(err,result)=>{
if(err){
reject(err)
}else{
resolve(result)
}
})
})
}
- 在注册接口中将传回来的密码进行加密
const signup = async (req, res, next) => {
res.set('content-type', 'application/json;charset=utf-8')
const { username, password } = req.body
//进行密码加密
const bcryptPaaword = await hash(password)
const isexit = await UserModel.findOne({ username })
if (isexit) {
res.render('fail', {
data: '用户名已存在!'
})
} else {
const result = await UserModel.signup({ username, password: bcryptPaaword })
res.render('suc', {
data: JSON.stringify(
{
msg: '注册成功'
}
)
})
}
}
登录接口进行解析的方法在下面的鉴权中会一并说明
Cookie-Session鉴权
在服务端将用户名或其他信息生成session,每次用户请求时进行信息比对进行鉴权。
- 首先安装cookie-session第三方包
yarn add cookie-session
- 在app.js中进行注册
var cookieSession = require('cookie-session')
app.use(cookieSession({
name: 'session',
keys: ['key1', 'key2']
}))
这块有个坑,这里的注册需要在路由注册的上方,否则会报错。
- 注册成功之后,在每次登录成功之后的代码中进行session的存储。
const login = async (req, res, next) => {
res.set('content-type', 'application/json;charset=utf-8')
const { username, password } = req.body
const result = await UserModel.findOne({ username })
if (result) {
const { password: hashPassword } = result
//hash加密后进行密码的比对
const isTrue = await compare(password, hashPassword)
if (isTrue) {
req.session.username=username
res.render('suc', {
data: JSON.stringify({
msg: '登录成功',
username,
token
})
})
} else {
res.render('fail', {
data: JSON.stringify({
msg: '用户名或密码错误'
})
})
}
} else {
res.render('fail', {
data: JSON.stringify({
msg: '用户名或密码错误'
})
})
}
}
- 创建鉴权中间件
新建一个auth.js,让需要鉴权的请求在每次请求前先经过auth鉴权,如果此前存储的username存在,则鉴权通过,否则返回让用户重新登录的信息
const auth=(req,res,next)=>{
if(req.session.username){
//放行,继续请求
next()
}else{
res.render('auth', {
data: JSON.stringify({
msg: '无权限!请登录!'
})
})
}
}
//在routes中,进行list请求前先经过auth请求
router.get('/list', auth,list)
使用cookie-session进行鉴权现在用法比较少,理由是多用户使用下,持续在服务器中存储session会造成服务器压力过大,目前比较流行的鉴权方式是token
Token鉴权
token鉴权是在用户登录成功之后,生成token返回给前端。之后前端每一次请求,都需要携带token,如果通过验证即可继续进行请求,token不必存储在服务器,由前端自行通过浏览器存储技术进行存储。
- 安装jsonwebtokn包
yarn add jsonwebtoken
token的加密有对称加密和非对称加密。
简单来说,对称加密其实就是加密和解密时所使用的密钥一致,非对称加密就是不一致,这块的非对称加密我们使用公钥和私钥。
- 安装openssl
下载地址:http://slproweb.com/products/Win32OpenSSL.html
这块的安装和设置环境变量不再赘述,自行百度或查看此文章
https://blog.csdn.net/qq_39081974/article/details/81059022 - 创建keys文件夹,在里面执行以下命令,创建公钥和私钥
利用 openssl 生成公钥私钥
生成公钥: openssl genrsa -out rsa_private_key.pem 1024
生成私钥: openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem
- 创建token和解析token函数
exports.createToken=(username)=>{
//读取私钥,根据用户名和私钥生成token,生成私钥时需要传入一个算法
const private=fs.readFileSync(path.join(__dirname,'../keys/rsa_private_key.pem'))
let token=jwt.sign({username},private,{ algorithm: 'RS256' })
return token
}
exports.verifyToken=(token)=>{
//读取公钥,根据token和公钥解析token,不需要传入算法
const public=fs.readFileSync(path.join(__dirname,'../keys/rsa_public_key.pem'))
console.log(jwt.verify(token,public));
return jwt.verify(token,public)
}
- 在auth中进行鉴权
和上面cookie-session鉴权一样,需要由auth请求进行一个过滤
获取请求头中的token进行解析,若出错则直接返回无权限
const auth = (req, res, next) => {
const token = req.headers.token
try {
verifyToken(token)
next()
} catch (error) {
res.render('auth', {
data: JSON.stringify({
msg: '无权限!请登录!'
})
})
}
}