JWT
优质
小牛编辑
124浏览
2023-12-01
增加验证逻辑
我们不想要谁都可以访问 todo 、folder 的一些API,至少我们需要用户登陆了才可以访问,这个时候我们需要 JSON Web Token。
json 代表一种格式,web 代表所处的环境,token 代表一段加密好的字符串。
它的流程通常是这样,在没登录之前访问 todo 或者 folder 是不会给你任何数据的,当我们请求 login 或者 register 接口的时候,校验成功了之后 会返回一段token,之后我们去请求 todo 或者 folder的 API,但是在请求之前,我们要在请求头上面加上一个验证字段,而这个字段的值就是我们的token。
当服务器接收到拥有验证字段的请求头部的时候,服务器会校验这个token的有效性,就是先解密后再拿到里面的值,有的是里面还包含一个有效时间的属性,这里我们为了简单,就不添加超时时间字段了。
安装 koa-jwt 、jsonwebtoken
npm i koa-jwt@2 jsonwebtoken -S
koa-jwt 是服务器用来验证请求头的中间件,当有验证请求头的时候,它会把里面的数据解密了之后放到 ctx.state.user 这个对象里面。
jsonwebtoken 就是用来加密对象的库
修改 index.ts , 增加 koa-jwt 中间件
import * as Koa from 'koa';
import * as OtherParser from 'koa-better-body';
import * as bodyParser from 'koa-bodyparser';
import * as Convert from 'koa-convert';
import * as kjwt from 'koa-jwt';
import { api, router } from './router';
const app = new Koa();
app
.use(Convert(bodyParser()))
.use(Convert(OtherParser()))
.use(kjwt({secret: 'todo-app'}).unless({ path: [/^\/api\/v1\/(login|register)/] }))
.use(router.middleware())
.use(api.middleware())
.use(async (ctx, next) => {
console.log("state \n");
console.log(ctx.state);
await next();
})
.listen(3000, () => {
console.log("Server Stared on http://localhost:3000");
api.getRoutes().forEach((route) => {
console.log(`${route.method} http://localhost:3000${route.path}`)
})
});
修改 controller/user.ts 让他放回 token, 这个token 非常的简单,就是存储了我们的 user 信息。
import * as Koa from 'koa';
import UserUtil, { User } from '../model/user';
import * as ph from 'password-hash';
import * as jwt from 'jsonwebtoken';
var secret = 'todo-app';
function getFields(ctx: Koa.Context, next) : [string, string, string]{
try{
const { username, email, password } = ctx.request.fields
return [username, email, password];
}catch(e){
console.error(e);
ctx.status = 422;
ctx.body = '[Unprocesable entity] \n验证失败,必须传递 username/email/password 三个字段';
}
}
function exceptPassword(user: any){
user = JSON.parse(JSON.stringify(user));
if(user.password) delete user.password;
return user;
}
export default {
async register(ctx: Koa.Context, next) {
const [username, email, password] = getFields(ctx, next);
try{
const user = await UserUtil.createUser({
username,
email,
password
});
const ret = exceptPassword(user);
ctx.body = jwt.sign(ret, secret);
}catch (e){
console.error(e);
ctx.status = 422;
// ctx.body = '[Unprocesable entity] \n验证失败,' + e.errors[0].message;
}
await next();
},
async login(ctx: Koa.Context, next) {
const [_, email, password] = getFields(ctx, next);
ctx.status = 400;
try{
const db_user = await User.findOne({
where: {
email
}
});
if(ph.verify(password, db_user.password)){
ctx.status = 200;
const ret = exceptPassword(db_user);
ctx.body = jwt.sign(ret, secret);
}else{
ctx.body = "密码不正确";
}
}catch(e){
console.error(e);
// ctx.body = e.errors[0].message;
}
await next();
}
}
这样我们就保证了不是谁都可以请求我们的 todo 和 folder api 了。