前言
本内容是在egg框架中的相关实现,主要是在登录注册时利用bcrypt库对密码的处理,和利用egg-jwt实现token的生成和校验
一、登录注册实现
1,注册对密码加
注册主要是把用户提交的信息保存起来,重点是密码的处理,把密码加密后保存在数据库有利于更好地保护我们的用户信息。接下来,我们将使用Bcrypt为我们的用户密码加盐并散列。
Bcrypt早在1996年就存在,并且经过多年的大量网站的使用和验证,鲜有报道出来的问题。可以说他的这一套算法是很安全的。
散列(hash) 的意思是给一段普通文字使用算法加密,使他变成一个固定长度的字符串。不管这段文字有多长,经过算法处理后的最终的结果都将是相同长度。并且每次的结果都将完全相同。
盐 (salt) 是一个随机的字符串。如果你在hash的时候加入盐作为干扰的话,那么结果就不会再保持相同了。盐会被自动加到hash里面
js
// 安装bcryptjs
npm install bcryptjs
// 引入
const bcrypt = require('bcryptjs');
// 注册接口
register(params) {
// bcrypt 库 对密码加密
const { ctx } = this
const params = ctx.request.body
const saltRounds = 10
var hash = bcrypt.hashSync(params.password, saltRounds);
var user = await ctx.model.Users.create({ // 数据入库
name: params.name,
password: hash,
...params
});
ctx.success('注册成功')
}
saltRounds。saltRounds 代表加密所需的时间,saltRounds越大,加密所需时间越长,加密后的密码也就越安全。但是我们也不想让用户永远等着我们加密密码,所以一般使用默认值10就可以。
2,登录对密码校验和token下发
密码校验使用 bcrypt.compare(password1, password2) 返回布尔值,如果密码和hash吻合的话,就返回true,反之false。
生成token用 egg-jwt
js
// 安装
npm i egg-jwt -S
// 配置config/plugins.js
jwt: {
enable: true,
package: 'egg-jwt',
}
// 配置 config/config.default.js
config.jwt = {
secret: 'xxxxxxxxx', // 自定义 token 的加密条件字符串
expiresIn: '7d', // 过期时间
}
js
login() {
const { ctx, app } = this
// 查询数据库是否有该用户
var targetUser = await ctx.model.Users.findOne({
where: {
account: params.account
}
});
if (!targetUser) { // 用户不存在
return ctx.error('用户或密码错误');
}
const params = ctx.request.body
// 密码一致性校验。password1用户提交的密码,password2是数据库保存的密码(一串hash密文)
const match = await bcrypt.compare(params.password, targetUser.dataValues.password);
// 返回**布尔值**,如果密码和hash吻合的话,就返回true,反之false。
if (match) {
// 获取config中jwt配置
const { secret, expiresIn } = app.config.jwt;
// 生成token,往token里存储用户信息,secret'秘钥,expiresIn 过期时间
const token = app.jwt.sign(targetUser.dataValues, secret, { expiresIn });
// 把token返回前端
targetUser.dataValues.token = token;
// 过滤返回数据 密码,删除时间
delete targetUser.dataValues.password;
ctx.success(targetUser)
} else {
return ctx.error('用户或密码错误');
}
}
3,接口需要token校验的话,在路由中间件注入jwt,请求头需要加上Authorization: Bearer + 空格 + token
js
// routes/users.js
module.exports = app => {
const { router, controller, jwt } = app;
// 获取用户列表
router.get("xxx/list", jwt, controller.users.getUserList); // jwt以中间件注入,在调用时会触发token校验
4,无感刷新token
1, 使用两个token: accessToken和refreshToken
- accessToken用来鉴权,其有效期很短,即使被盗,影响也较小
- refreshToken只用来刷新accessToken的时间.其有效期很长,作用只是用来刷新token,即使被盗影响也不大
新增刷新接口
js
// 签发无感刷新使用的token
function generateReFreshToken(user) {
const refreshOptions = {
expiresIn: '10d'
}
const payload = { username: user.username };
return jwt.sign(payload, secret, refreshOptions);
}
// 无感刷新token。该接口需要带上refreshToken,jwt会验证refreshToken是否过期
app.get('/refreshToken', jwt, (req,res) => {
const {username,password} = req.user
// 新token
const token = generateToken({username,password})
// 新refreshToken
const refreshToken = generateReFreshToken({username,password})
res.send({
data: {
token,refreshToken
},
success: true,
})
})
//登录接口也要改一下 登录时将refreshToken也返回