文章目录
-
-
- 1. 数据库创建
- 2. 创建一个thinkjs项目
- 3. 配置项目数据库
- 4. 用户的登录验证实现
-
1. 数据库创建
用Navicat创建一个数据库“db”,在创建一张存储用户登录信息的表,命名为“demo-admin”,
表的设计如下(表直接拿“hioshop”开源项目中的admin表):
hioshop-server
| id | username | password | password_salt | last_login_ip | last_login_time | is_delete |
|---|---|---|---|---|---|---|
| 14 | hiolabs | 4af5d2d0e6c2bd03dca28c884afdf0ee | HIOLABS |
2. 创建一个thinkjs项目
thinkjs new demo-server//创建一个thinkjs项目
3. 配置项目数据库
找到项目‘src/config/adapter.js’文件,打开这个文件,修改代码如下:
mysql: {
handle: mysql,//mysql数据库
database: 'db',//数据库名
prefix: 'demo_',//数据表前缀,如果一个数据库里有多个项目,那项目之间的数据表可以通过前缀来区分
encoding: 'utf8mb4',//数据库编码方式
host: '127.0.0.1',//主机ip
port: '3306',//端口号
user: 'root',//用户名
password: '123123123',//密码
dateStrings: true
}
4. 用户的登录验证实现
//创建一个"auth.js"的controller控制器
thinkjs controller auth
//创建一个"token.js"的Service对象,用来定义token验证的相关方法
thinkjs service token
假设客户端向服务端发送一个post请求携带用户名和密码的请求‘/auth/login’接口,服务端对当前
请求进行验证,验证通过则往下继续执行,相关验证代码如下:
//"auth.js"
const Base = require('./base.js');
module.exports = class extends Base {
async loginAction(){ //登录验证
//获取前端提交过来的用户名,并定义一个常量存储它
const username = this.post('username');
//获取前端提交过来的密码,并定义一个常量存储它
const password = this.post('password');
//对用户名进行验证
const admin = await this.model('admin').where({ username:username}).find();
if(think.isEmpty(admin)){
return this.fail(401,'用户名不正确');
}
//对用户密码进行验证
if(think.md5(password + '' + admin.password_salt) !== admin.password){
return this.fail(401,'用户密码错误');
}
//用户名和密码都正确的话,更新当前用户的登录时间和登录ip到记录对应的数据表相应字段中
await this.model('admin').where({ id:admin.id}).update({
last_login_time:parseInt(Date.now()/1000),
last_login_ip:this.ctx.ip
});
//实例化一个tokenservice对象,来调用create()方法创建一个token
const TokenService = this.service('token');
const token = await TokenService.create({
id:admin.id//payload
});
//判断token是否创建成功
if(think.isEmpty(token)){
return this.fail('用户登录失败');
}
//令牌创建成功,返回给客户端"uerInfo"和"token"给前端
const userInfo = {
id:admin.id,
username:admin.username
};
return this.success({
token:token,
userInfo:userInfo
});
}
};
//"token.js"
const jwt = require('jsonwebtoken');//JWT
const secret = '&w@ueJnXy!Gj0J@qVmMPR^9ip00EP0^Qy5Se#lzwStExJ3Zw4j02NVLm^btjBO8x'
module.exports = class extends think.Service {
async create(userId){ //创建令牌
const token = jwt.sign(userId,secret);
return token;
}
async parse(){ //令牌验签
if(think.isEmpty(think.token)){ //如果token为空
return null;
}
else{
try{
return jwt.verify(think.token,secret).id;
}catch(err){
return null;
}
}
}
};
通过以上操作后端接口‘auth/login’将token返回给客户端,假设客户端获取到服务端响应的token,
把token值存储在header请求头'Authorization'中,便于每次请求路由时携带token发送到服务端
接着实现对每次请求的token验证是否合法的实现,代码如下:
//base.js
module.exports = class extends think.Controller {
async _before(){ //_before()方法在访问每条路由前都会先执行此函数
//从客户端请求头header中获取发送过来的token,如果没有获取到给think.token赋空值
think.token = this.ctx.header['Authorization'] || '';
//声明一个Token实例来调用token.js里的parse()方法来对token进行验签,通过则返回用户ID,失败返回null
const Token = this.service('token');
think.userId = await Token.parse();
if(this.ctx.controller !== 'auth'){ //如果当前路由不是'/auth'且
if(think.isEmpty(think.userId)){ //如果用户ID为空
return this.fail('用户未登录');
}
}
}
};




