/**
|
鉴权验证
|
*/
|
"use strict";
|
|
import { Context } from "egg";
|
import { SysUserLog } from "../entity/sys/core/sysUserLog";
|
import { LoginInfo } from "../entity/sys/loginInfo";
|
import moment = require("moment");
|
import { BaseConsignor } from "../entity/basicInfo/consignor/baseConsignor";
|
import * as ip from "ip";
|
import { PlatUserProduct } from "../entity/sys/plat/platUserProduct";
|
|
//#region ApiAuth
|
/**
|
* 内部API接口
|
* @param ctx 上下文
|
*/
|
let apiAuth = async (ctx: Context): Promise<boolean> => {
|
let { app } = ctx;
|
let userRedis = app.redis.clients.get("userInfo");
|
let dbRead = ctx.service.common.dbRead;
|
await ctx.service.common.checkDbConnection(); // 校验数据库正确连接
|
|
let guid = ctx.header.guid,
|
timestamp = "",
|
nonce = "",
|
signature = "",
|
accessToken = ctx.header.accesstoken;
|
|
var accessTokenKey = "AccessToken_" + guid;
|
var signTokenKey = "Token_" + guid;
|
if (accessToken) {
|
//客户端授权Token
|
var _AccessTokenServer = "";
|
if (userRedis) {
|
_AccessTokenServer = await userRedis.get(accessTokenKey);
|
}
|
//如果缓存没有,在去访问日志里获取
|
if (!_AccessTokenServer) {
|
var log = await dbRead.findOne(SysUserLog, {
|
where: {
|
gUID: guid
|
},
|
order: { log_Id: "DESC" }
|
});
|
if (log && log.loginInfo) {
|
_AccessTokenServer = log.loginInfo;
|
// 保留7天
|
userRedis && (await userRedis.set(accessTokenKey, _AccessTokenServer, "EX", 7 * 24 * 60 * 60));
|
|
if (log.signTokenInfo) {
|
var signTokenInfo = JSON.stringify(log.signTokenInfo);
|
// 保留7天
|
userRedis && (await userRedis.set(signTokenKey, signTokenInfo, "EX", 7 * 24 * 60 * 60));
|
}
|
}
|
}
|
|
if (_AccessTokenServer != null) {
|
let platUserInfo: LoginInfo | undefined = undefined;
|
try {
|
platUserInfo = ctx.helper.objectToCase(JSON.parse(_AccessTokenServer)) as LoginInfo;
|
} catch (error) {
|
userRedis && (await userRedis.set(accessTokenKey, null));
|
}
|
if (!platUserInfo || platUserInfo.accessToken != accessToken) {
|
ctx.body = {
|
statusCode: 401,
|
msg: "Unauthorized-客户端授权不正确"
|
};
|
return false;
|
}
|
} else {
|
ctx.body = {
|
statusCode: 401,
|
msg: "Unauthorized-服务器授权不存在"
|
};
|
return false;
|
}
|
} else {
|
ctx.body = {
|
statusCode: 401,
|
msg: "Unauthorized-客户端未获取到授权"
|
};
|
return false;
|
}
|
|
timestamp = ctx.header.timestamp;
|
nonce = ctx.header.nonce;
|
signature = ctx.header.signature;
|
|
//判断请求头是否包含以下参数
|
if (!guid || !timestamp || !nonce || !signature) {
|
ctx.body = {
|
statusCode: 401,
|
msg: "ParameterError-请求参数不完整或不正确"
|
};
|
return false;
|
}
|
|
//判断timespan是否有效
|
let ts1 = parseFloat(timestamp);
|
let ts2 = moment(new Date()).valueOf();
|
let ts = ts2 - ts1;
|
let flag = ts < 30 * 60 * 1000; //30分钟有效
|
if (!flag) {
|
ctx.body = {
|
statusCode: 407,
|
msg: "URLExpireError-时间戳失效"
|
};
|
|
return false;
|
}
|
|
//判断token是否有效
|
let cacheKey = "Token_" + guid;
|
let token = userRedis && (await userRedis.get(cacheKey));
|
let signtoken = "";
|
if (!token) {
|
ctx.body = {
|
statusCode: 403,
|
msg: "TokenInvalid-请求TOKEN失效"
|
};
|
return false;
|
} else {
|
try {
|
token = JSON.parse(token);
|
signtoken = token.signToken;
|
if (!signtoken) {
|
userRedis && (await userRedis.set(cacheKey, null));
|
return false;
|
}
|
} catch (error) {
|
userRedis && (await userRedis.set(cacheKey, null));
|
return false;
|
}
|
}
|
|
//根据请求类型拼接参数
|
let data = ctx.request.body;
|
let headerParams = timestamp + nonce + guid + signtoken;
|
let nodatasign = ctx.header.nodatasign;
|
if (nodatasign) {
|
data.noDataSign = true;
|
}
|
let sign = ctx.helper.getSignature(headerParams, data);
|
if (sign !== signature) {
|
ctx.body = {
|
statusCode: 406,
|
msg: "TokenInvalid-HTTP请求不合法,请求参数不合法"
|
};
|
// 记录日志到mongodb
|
try {
|
let db = app.mongodb;
|
let collection = db.collection("apiCheckAuth");
|
collection.insertOne({
|
type: "user",
|
ip: ip.address(),
|
headerParams: headerParams,
|
data: data,
|
sign: sign,
|
timestamp: timestamp,
|
nonce: nonce,
|
token: token,
|
signature: signature
|
});
|
} catch { }
|
|
return false;
|
}
|
|
return true;
|
};
|
//#endregion
|
|
//#region consignorAuth
|
/**
|
* 货主API接口
|
* @param ctx 上下文
|
*/
|
let consignorAuth = async (ctx: Context): Promise<boolean> => {
|
let { app } = ctx;
|
let userRedis = app.redis.clients.get("userInfo");
|
await ctx.service.common.checkDbConnection(); // 校验数据库正确连接
|
|
let dbRead = ctx.service.common.dbRead;
|
let consignorCode = ctx.header.consignorcode;
|
let token = ctx.header.token;
|
let timestamp = ctx.header.timestamp;
|
let nonce = ctx.header.nonce;
|
let signature = ctx.header.signature;
|
|
//判断请求头是否包含以下参数
|
if (!consignorCode || !token || !timestamp || !nonce || !signature) {
|
ctx.body = {
|
statusCode: 401,
|
msg: "ParameterError-请求参数不完整或不正确"
|
};
|
return false;
|
}
|
|
//判断timespan是否有效
|
let ts1 = parseFloat(timestamp);
|
let ts2 = moment(new Date()).valueOf();
|
let ts = ts2 - ts1;
|
let flag = ts < 30 * 60 * 1000; //30分钟有效
|
if (!flag) {
|
ctx.body = {
|
statusCode: 407,
|
msg: "URLExpireError-时间戳失效"
|
};
|
|
return false;
|
}
|
|
//根据请求类型拼接参数
|
let data = ctx.request.body;
|
let headerParams = consignorCode + timestamp + nonce + token;
|
let sign = ctx.helper.getSignature(headerParams, data);
|
if (sign !== signature) {
|
ctx.body = {
|
statusCode: 406,
|
msg: "TokenInvalid-HTTP请求不合法"
|
};
|
// 记录日志到mongodb
|
try {
|
let db = app.mongodb;
|
let collection = db.collection("apiCheckAuth");
|
collection.insertOne({
|
type: "consignor",
|
ip: ip.address(),
|
headerParams: headerParams,
|
data: data,
|
sign: sign,
|
consignorCode: consignorCode,
|
timestamp: timestamp,
|
nonce: nonce,
|
token: token,
|
signature: signature
|
});
|
} catch { }
|
|
return false;
|
}
|
|
//验证账号是否正确
|
var signTokenKey = "consignorToken_" + token;
|
var conInfo = userRedis && (await userRedis.get(signTokenKey)); // (Base_Consignor)HttpRuntime.Cache[signTokenKey];
|
if (!conInfo) {
|
conInfo = await dbRead.findOne(BaseConsignor, {
|
where: {
|
consignorCode: consignorCode,
|
token: token
|
}
|
});
|
if (conInfo) {
|
ctx.logger.info("apiCheckAuth,conInfo=", JSON.stringify(conInfo));
|
userRedis && (await userRedis.set(signTokenKey, JSON.stringify(conInfo), "EX", 7 * 24 * 60 * 60));
|
}
|
} else {
|
conInfo = JSON.parse(conInfo);
|
}
|
|
if (!conInfo) {
|
ctx.body = {
|
statusCode: 409,
|
msg: "ConsignorError-货主账号不正确"
|
};
|
return false;
|
}
|
//logger.Info("身份验证:验证完成");
|
|
return true;
|
};
|
//#endregion
|
|
//#region clientAuth
|
/**
|
* 对外账套API接口
|
* @param ctx 上下文
|
*/
|
let clientAuth = async (ctx: Context): Promise<boolean> => {
|
let { app } = ctx;
|
let userRedis = app.redis.clients.get("userInfo");
|
await ctx.service.common.checkDbConnection(); // 校验数据库正确连接
|
|
let dbRead = ctx.service.common.dbRead;
|
let appKey = ctx.header.appkey;
|
let appSecret = ctx.header.appsecret;
|
let timestamp = ctx.header.timestamp;
|
let nonce = ctx.header.nonce;
|
let signature = ctx.header.signature;
|
|
//判断请求头是否包含以下参数
|
if (!appKey || !appSecret || !timestamp || !nonce || !signature) {
|
ctx.body = {
|
statusCode: 401,
|
msg: "ParameterError-请求参数不完整或不正确"
|
};
|
return false;
|
}
|
|
//判断timespan是否有效
|
let ts1 = parseFloat(timestamp);
|
let ts2 = moment(new Date()).valueOf();
|
let ts = ts2 - ts1;
|
let flag = ts < 30 * 60 * 1000; //30分钟有效
|
if (!flag) {
|
ctx.body = {
|
statusCode: 407,
|
msg: "URLExpireError-时间戳失效"
|
};
|
|
return false;
|
}
|
|
//根据请求类型拼接参数
|
let data = ctx.request.body;
|
let headerParams = appKey + timestamp + nonce + appSecret;
|
let sign = ctx.helper.getSignature(headerParams, data);
|
if (sign !== signature) {
|
ctx.body = {
|
statusCode: 406,
|
msg: "TokenInvalid-HTTP请求不合法"
|
};
|
// 记录日志到mongodb
|
try {
|
let db = app.mongodb;
|
let collection = db.collection("apiCheckAuth");
|
collection.insertOne({
|
type: "client",
|
ip: ip.address(),
|
headerParams: headerParams,
|
data: data,
|
sign: sign,
|
appKey: appKey,
|
timestamp: timestamp,
|
nonce: nonce,
|
appSecret: appSecret,
|
signature: signature
|
});
|
} catch { }
|
|
return false;
|
}
|
|
//验证账号是否正确
|
var signTokenKey = "clientToken_" + appSecret;
|
var conInfo = userRedis && (await userRedis.get(signTokenKey)); // (Base_Consignor)HttpRuntime.Cache[signTokenKey];
|
if (!conInfo) {
|
conInfo = await dbRead.findOne(PlatUserProduct, {
|
where: {
|
appKey: appKey,
|
appSecret: appSecret
|
}
|
});
|
if (conInfo) {
|
ctx.logger.info("clientAuth,conInfo=", JSON.stringify(conInfo));
|
userRedis && (await userRedis.set(signTokenKey, JSON.stringify(conInfo), "EX", 7 * 24 * 60 * 60));
|
}
|
} else {
|
conInfo = JSON.parse(conInfo);
|
}
|
|
if (!conInfo) {
|
ctx.body = {
|
statusCode: 409,
|
msg: "ConsignorError-接口账号不正确"
|
};
|
return false;
|
}
|
//logger.Info("身份验证:验证完成");
|
|
return true;
|
};
|
//#endregion
|
|
module.exports = options => {
|
const { actions } = options;
|
|
return async function apiCheckAuth(ctx: Context, next) {
|
let apitype = ctx.header.apitype;
|
let url = ctx.request.path.toLowerCase();
|
if (ctx.method === "OPTIONS") {
|
await next();
|
return;
|
}
|
|
// 跳过鉴权
|
for (let action of actions) {
|
action = action.toLowerCase();
|
if (action.indexOf("*") >= 0) {
|
action = action.replace("*", "");
|
if (url.indexOf(action) >= 0) {
|
await next();
|
return;
|
}
|
} else if (action === url) {
|
await next();
|
return;
|
}
|
}
|
|
let result = false;
|
if (apitype === "consignor") {
|
result = await consignorAuth(ctx);
|
} else if (apitype === "client") {
|
result = await clientAuth(ctx);
|
} else {
|
result = await apiAuth(ctx);
|
}
|
|
if (!result) {
|
return;
|
}
|
|
await next();
|
};
|
};
|