138 lines
3.5 KiB
JavaScript
138 lines
3.5 KiB
JavaScript
"use strict";
|
|
|
|
import crypto from "crypto"
|
|
import logger from './logger.js'
|
|
|
|
function AuthToken() {
|
|
}
|
|
|
|
AuthToken.prototype.init = function (redisdb, defaultExpiresSeconds) {
|
|
this.tokenDB = redisdb;
|
|
this.defaultExpiresSeconds = defaultExpiresSeconds;
|
|
}
|
|
|
|
AuthToken.prototype.gen = async function (uid, tokenOld) {
|
|
let userToken = tokenOld;
|
|
|
|
try {
|
|
let tokenData = await this.tokenDB.get(userToken).then(function (data) {
|
|
return JSON.parse(data);
|
|
});
|
|
if (!tokenData) {
|
|
if (!userToken || userToken.length <= 16) {
|
|
let hash = crypto.createHash("md5");
|
|
hash.update(uid + Date() + Math.random());
|
|
userToken = hash.digest("hex");
|
|
}
|
|
|
|
tokenData = {
|
|
uid,
|
|
token: userToken,
|
|
ts: Math.floor(Date.now() / 1000),
|
|
ttl: this.defaultExpiresSeconds,
|
|
};
|
|
}
|
|
|
|
this.tokenDB.set(userToken, JSON.stringify(tokenData), "EX", this.defaultExpiresSeconds);
|
|
} catch (err) {
|
|
logger.error('生成Token失败:', { error: err.message, uid, stack: err.stack });
|
|
}
|
|
|
|
return userToken;
|
|
};
|
|
|
|
AuthToken.prototype.update = async function (userToken) {
|
|
try {
|
|
let tokenData = await this.tokenDB.get(userToken).then(function (data) {
|
|
return JSON.parse(data);
|
|
});
|
|
|
|
if (tokenData) {
|
|
this.tokenDB.set(userToken, JSON.stringify(tokenData), "EX", this.defaultExpiresSeconds);
|
|
return tokenData;
|
|
}
|
|
} catch (err) {
|
|
logger.error('更新Token失败:', { error: err.message, stack: err.stack });
|
|
}
|
|
|
|
return null;
|
|
};
|
|
|
|
AuthToken.prototype.del = async function (userToken) {
|
|
let tokenData = await this.tokenDB.get(userToken).then(function (data) {
|
|
return JSON.parse(data);
|
|
});
|
|
|
|
if (tokenData) {
|
|
this.tokenDB.del(userToken);
|
|
}
|
|
|
|
return tokenData;
|
|
};
|
|
|
|
AuthToken.prototype.check = async function (userToken, updateExpire = true) {
|
|
try {
|
|
if (updateExpire) {
|
|
if (await this.tokenDB.expire(userToken, this.defaultExpiresSeconds) >= 1) {
|
|
return true;
|
|
}
|
|
} else {
|
|
if (await this.tokenDB.exists([userToken]) >= 1) {
|
|
return true;
|
|
}
|
|
}
|
|
} catch (err) {
|
|
logger.error('检查Token失败:', { error: err.message, userToken, stack: err.stack });
|
|
}
|
|
return false;
|
|
};
|
|
|
|
AuthToken.prototype.get = async function (token) {
|
|
let tokenData = await this.tokenDB.get(token).then(function (data) {
|
|
return JSON.parse(data);
|
|
});
|
|
|
|
if (!tokenData) {
|
|
return null;
|
|
}
|
|
|
|
return tokenData;
|
|
};
|
|
|
|
AuthToken.prototype.koaRequest = async function (ctx, next) {
|
|
try {
|
|
let token = ctx.request.body.token;
|
|
|
|
if (!token) token = ctx.request.query.token;
|
|
if (!token) token = ctx.header["authorization"];
|
|
if (!token) token = ctx.header["token"];
|
|
|
|
if (!token) {
|
|
throw new Error("Need token param.");
|
|
}
|
|
|
|
let ret = await this.check(token);
|
|
if (!ret) {
|
|
throw new Error("User not login in.");
|
|
}
|
|
|
|
let tokenData = await this.get(token);
|
|
if (tokenData && tokenData.uid) {
|
|
const { DBModel } = await import("../models/index.js");
|
|
const user = await DBModel.User.findOne({ _id: tokenData.uid });
|
|
if (user) {
|
|
ctx.userInfo = user;
|
|
}
|
|
}
|
|
|
|
ctx.authToken = this;
|
|
|
|
return next();
|
|
} catch (err) {
|
|
logger.error('身份验证失败:', { error: err.message, token: ctx.request.body.token || ctx.request.query.token || ctx.header["authorization"] || ctx.header["token"], stack: err.stack });
|
|
throw err;
|
|
}
|
|
};
|
|
|
|
const Token = new AuthToken()
|
|
export { Token } |