sdk: 登录

This commit is contained in:
luying
2021-11-08 17:47:30 +08:00
parent a251ce47fa
commit fb6a5a785e
12 changed files with 291 additions and 60 deletions

View File

@@ -14,8 +14,6 @@ import { pushComposeOrangeHero, pushHeroQualityUpMsg, pushHeroStarMax, pushHeroW
import { calculatetopLineup, calEquipSeids } from '../../../pubUtils/playerCe';
import { PvpDefenseModel } from '../../../db/PvpDefense';
import { checkTaskWithHero, checkTask, checkActivityTask } from '../../../services/taskService';
import { addSkin } from '../../../pubUtils/itemUtils';
import Skin from '../../../db/Skin';
import { EquipModel, EquipType } from '../../../db/Equip';
import { checkEquipCanPut } from '../../../services/equipService';
import { pick } from 'underscore';

View File

@@ -11,3 +11,16 @@ export enum BANTU_VID_ADDR {
REPORT_ONLINE = '/addiction_prevention/report_online'
}
export const BANTU_VID_APP_KEY = '05c1c495369769e3c5d98426e9c8c2c0';
export enum SDK_37_ADDR {
LOGIN = 'https://apimyh5.37.com/index.php?c=sdk-unified&a=validate'
}
export enum SDK_37_CONST {
GAME_ID = 165, // 研发使用的GAME_ID
PID = '37h5', // 37渠道标识
FX_C_GAME_ID = 21228, // 子游戏id
GAME_KEY = 'sgzzyz',
LOGIN_KEY = '3PerD)H!JdTC_pEUnZl8vXKgasj5;7Q~', // 登录KEY
PAY_KEY = '0;_Zy.qodXCF8NGQmrOYltk%HgfAz*39', // 重置KEY
CHAT_KEY = '3PerD)H!JdTC_pEUnZl8vXKgasj5;7Q~', // 聊天KEY
}

View File

@@ -30,6 +30,8 @@ export const STATUS = {
NAME_HAS_USED: { code: 10015, simStr: '该名字已使用' },
ROLE_HAS_INIT: { code: 10016, simStr: '该角色已初始过' },
ROLE_EXIST: { code: 10017, simStr: '账号已存在' },
CHANNEL_ERR: { code: 10018, simStr: '无此渠道' },
VALIDATE_ERR: { code: 10019, simStr: '渠道校验错误' },
// 战斗相关状态 20000 - 29999
// 战斗通用 20000 - 20099
BATTLE_MISS_INFO: { code: 20001, simStr: '缺少关卡信息' },

View File

@@ -3,6 +3,7 @@ import { CounterModel } from './Counter';
import BaseModel from './BaseModel';
import { index, getModelForClass, prop, DocumentType } from '@typegoose/typegoose';
import { genCode, aesEncryptcfb, aesDecryptcfb } from '../pubUtils/util';
import { LoginValidateData37, ChannelInfo } from '../domain/sdk';
const bcrypt = require('bcrypt');
const SALT_WORK_FACTOR = 5
@@ -18,6 +19,7 @@ class PlatForm {
*/
@index({ tel: 1 })
@index({ uid: 1 })
@index({ channelId: 1 })
export default class User extends BaseModel {
@prop({ required: true })
@@ -32,6 +34,15 @@ export default class User extends BaseModel {
@prop({ required: true })
token: string;
@prop({ required: true })
channelType: string; // 渠道类型
@prop({ required: true })
channelId: string; // 渠道类型
@prop({ required: true, _id: false })
channelInfo: LoginValidateData37|{}; // 渠道数据
@prop({ required: true, set: (val: string) => aesEncryptcfb(val, ENCRYPT_KEY, ENCRYPT_IV), get: (val: string) => aesDecryptcfb(val, ENCRYPT_KEY, ENCRYPT_IV) })
tel: string; // 账号
@@ -44,9 +55,6 @@ export default class User extends BaseModel {
@prop({ required: true })
salt: string;
@prop({ required: true, default: '' })
channelId: string;
// 游客相关
@prop({ required: false, default: false })
isGuest: boolean; // 是否是游客
@@ -123,6 +131,20 @@ export default class User extends BaseModel {
return user;
}
public static async createUserWithChannel(channelId: string, channelType: string, channelInfO: ChannelInfo, token: string, platform: string, pkgName: string, serverType: string, deviceId: string, ip: string = '') {
const curTime: Date = new Date();
const uid = await CounterModel.getNewCounter(COUNTER.UID);
const userCode = genCode(8);
const doc = new UserModel();
let update = {};
update = Object.assign(update, doc.toJSON(), { platform, pkgName, serverType, createTime: curTime, uid, userCode, username: `用户${uid}`, token, lastLoginTime: curTime, ip, channelInfO, channelType });
delete update["device"];
const user: UserType = await UserModel.findOneAndUpdate({ channelId }, { $set: update, $addToSet: { device: deviceId } }, { upsert: true, new: true }).lean({ getters: true });
return user;
}
public static async getLastDeviceGuest(deviceId: string, token: string) {
const user: UserType = await UserModel.findOneAndUpdate({ device: { $elemMatch: { $eq: deviceId } }, isGuest: true }, { token }, { new: true }).sort({ createTime: -1 }).lean({ getters: true });
return user;
@@ -136,11 +158,23 @@ export default class User extends BaseModel {
return user;
}
public static async updateTokenByChannel(channelId: string, token: string, deviceId: string, ip: string, channelInfo: ChannelInfo) {
const curTime: Date = new Date();
let user = await UserModel.findOneAndUpdate({ channelId }, { $set: { token, lastLoginTime: curTime, ip, channelInfo }, $addToSet: { device: deviceId } }, { new: true }).lean({ getters: true });
return user;
}
public static async updateGetuiCID(tel: string, cid: string) {
let user = await UserModel.findOneAndUpdate({ tel }, { $set: { getuiCID: cid } }, { new: true }).lean({ getters: true });
return user;
}
public static async updateGetuiCIDByChannel(channel: string, cid: string) {
let user = await UserModel.findOneAndUpdate({ channel }, { $set: { getuiCID: cid } }, { new: true }).lean({ getters: true });
return user;
}
public static async createOrUpdate(isGuest: boolean, tel: string, token: string, platform: string, pkgName: string, serverType: string, deviceId: string, ip: string) {
// console.log(tel);
@@ -153,6 +187,18 @@ export default class User extends BaseModel {
return user;
}
public static async createOrUpdateChannelUser(channelId: string, channelType: string, channelInfo: ChannelInfo, token: string, platform: string, pkgName: string, serverType: string, deviceId: string, ip: string) {
// console.log(tel);
let user: UserType = await UserModel.findUserByChannel(channelId);
if (!user) {
user = await UserModel.createUserWithChannel(channelId, channelType, channelInfo, token, platform, pkgName, serverType, deviceId, ip);
} else {
user = await UserModel.updateTokenByChannel(channelId, token, deviceId, ip, channelInfo);
}
return user;
}
private static async encryptPass(password: string, salt?: string) {
if (!salt) {
salt = await bcrypt.genSalt(SALT_WORK_FACTOR);
@@ -191,6 +237,11 @@ export default class User extends BaseModel {
return user;
}
public static async findUserByChannel(channelId: string) {
const user: UserType = await UserModel.findOne({ channelId }).select('uid token serverType auth tel userCode pkgName ip').lean({ getters: true });
return user;
}
public static async findTokenByTel(tel: string) {
const user: UserType = await UserModel.findOne({ tel }).lean();
return user ? user.token : null;

42
shared/domain/sdk.ts Normal file
View File

@@ -0,0 +1,42 @@
import { prop } from "@typegoose/typegoose";
// 37的登录验证返回参数
export class LoginValidateData37 {
@prop({ required: true })
uid: number; // 用户uid
@prop({ required: true })
is_phone_bind: number; // 是否绑定手机
@prop({ required: true })
is_idcard_bind: number; // 是否绑定身份证
@prop({ required: true })
is_adult: number; // 是否成年
@prop({ required: true })
vip_level: number; // vip等级
@prop({ required: true })
is_youke: number; // 是否为第三方来源
@prop({ required: true })
is_bind_alias: number; // 是否绑定平台个性账号
@prop({ required: true })
birth: number; // 用户生日
@prop({ required: true })
age: number; // 用户年龄
@prop({ required: true })
unique_realname_id: string; // 用户身份证唯一标识
}
export interface LoginValidataReturn37 {
code: number;
msg: string;
data: LoginValidateData37;
}
export type ChannelInfo = LoginValidataReturn37|{};

View File

@@ -1,9 +1,65 @@
import * as request from "request-promise";
import * as crypto from 'crypto'
import { BANTU_VID_ADDR, BANTU_VID_APP_KEY } from '../consts';
import { BANTU_VID_ADDR, BANTU_VID_APP_KEY, HTTP_METHOD } from '../consts';
// 通用请求http
export async function httpRequest(url: string, method: string, headers: any, body: any) {
console.log(`httpRequest*********: ${url}, ${method}, ${JSON.stringify(headers)}, ${JSON.stringify(body)}`)
let options = {
url,
method,
headers,
body,
json: true
}
try {
let res = await request(options);
console.log('*****request result*****');
console.log(JSON.stringify(res));
return res;
} catch (e) {
console.error(e);
return false
}
}
export function md5(str: string, treatStr?: (str: string) => string) {
if(treatStr) str = treatStr(str);
console.log('*****str', str)
return crypto.createHash('md5').update(str, 'utf8').digest("hex");
};
export function getMd5ObjSign(obj: any, joinMark: string, treatStr?: (str: string) => string) {
const str = [];
Object.keys(obj).sort().forEach((key) => {
if (key == 'sign') {
} else {
str.push(key + '=' + obj[key]);
}
});
if (str.length == 0) {
console.error('check obj', obj);
}
var strs = str.join(joinMark);
return md5(strs, treatStr);
}
export async function checkMd5Sign(obj: any, treatStr?: (str: string) => string) {
if (getMd5ObjSign(obj, '', treatStr) === obj.sign) {
return true;
}
console.warn('correct sign:', getMd5ObjSign(obj, '', treatStr), obj.sign);
return false;
}
/************** 厚土防沉迷接口 **************/
/**
* 在线报告
* 在线报告 暂时不使用
* @param userCode 账号
* @param packageName 包名
*/
@@ -24,7 +80,7 @@ export async function reportOnline(userCode: string, packageName: string) {
}
/**
* 实名认证
* 实名认证 暂时不使用
* @param name 真实姓名
* @param idNum 身份证号
* @param userCode 账号
@@ -50,7 +106,7 @@ export async function authenticate(name: string, idNum: string, userCode: string
}
export async function vidHttpRequest(addr: string, body: any) {
body['sign'] = getObjSign(body);
body['sign'] = getVidObjSign(body);
console.log('body: ', JSON.stringify(body))
let options = {
@@ -62,7 +118,7 @@ export async function vidHttpRequest(addr: string, body: any) {
try {
let res = await request(options);
let check = checkSign(res);
let check = checkVidObjSign(res);
if (!check) return false;
// console.log('*****request result*****');
// console.log(JSON.stringify(res));
@@ -73,54 +129,38 @@ export async function vidHttpRequest(addr: string, body: any) {
}
}
export async function httpRequest(url: string, method: string, headers: any, body: any) {
console.log(`httpRequest*********: ${url}, ${method}, ${JSON.stringify(headers)}, ${JSON.stringify(body)}`)
let options = {
url,
method,
headers,
body,
json: true
}
try {
let res = await request(options);
console.log('*****request result*****');
console.log(JSON.stringify(res));
return res;
} catch (e) {
console.error(e);
return false
}
function getVidObjSign(body: any) {
return getMd5ObjSign(body, '', treatVid);
}
export function md5Vid(str: string) {
str = 'vId' + str;
return crypto.createHash('md5').update(str, 'utf8').digest("hex");
};
export function getObjSign(obj: any) {
const str = [];
Object.keys(obj).sort().forEach((key) => {
if (key == 'sign') {
} else {
str.push(key + '=' + obj[key]);
}
});
if (str.length == 0) {
console.error('check obj', obj);
}
var strs = str.join('');
return md5Vid(strs);
function checkVidObjSign(obj: any) {
return checkMd5Sign(obj, treatVid);
}
export async function checkSign(obj: any) {
if (getObjSign(obj) === obj.sign) {
return true;
}
console.warn('correct sign:', getObjSign(obj), obj.sign);
return false;
function treatVid(str) {
return 'vId' + str;
}
// 37sdk请求
function get37ObjSign(body: any, key: string) {
return getMd5ObjSign(body, '&', (str) => `${str}&${key}`);
}
export async function request37(url: string, body: any, key: string) {
// body = {
// clientid: 'abscddsssssss',
// pid: '37h5',
// game_id: 30,
// pst: 'MWNmY2pweWZ6dFRhZmdnZ1k4aHhINVUyZnFra1',
// time: 1583821808,
// c_game_id: 'com.a.test'
// }
// key = 'FkM619)t,P7E3yK#44q85)!Sm5cv8j'
body['sign'] = get37ObjSign(body, key);
let result = await httpRequest(url, HTTP_METHOD.POST, {}, body);
console.log('******result', result)
return result;
}

View File

@@ -0,0 +1,34 @@
import { SDK_37_ADDR, SDK_37_CONST } from '../consts';
import { request37 } from './httpUtil';
import { nowSeconds } from './timeUtil';
import { LoginValidataReturn37 } from '../domain/sdk';
/************** 37sdk **************/
export async function loginValidate37(clientId: string, pst: string) {
let result: LoginValidataReturn37 = await request37(SDK_37_ADDR.LOGIN, {
clientid: clientId,
pid: SDK_37_CONST.PID,
game_id: SDK_37_CONST.GAME_ID,
pst,
time: nowSeconds(),
c_game_id: SDK_37_CONST.FX_C_GAME_ID
}, SDK_37_CONST.LOGIN_KEY);
if (result && result.code !== 1) {
console.error(result.msg);
}
return result;
}
export async function loginValidata(channelType: string, clientId: string, pst: string) {
if(channelType == '37') {
return await loginValidate37(clientId, pst);
} else {
return false;
}
}
export function getChannelId(channelType: string, uid: number|string) {
return `${channelType}: ${uid}`;
}

View File

@@ -412,7 +412,7 @@ export function readFileAndParseJson(path: string) {
let readResult = readFile(path);
return JSON.parse(readResult);
} catch(e) {
throw new Error(`connectors.json 格式错误:${e.message}`);
throw new Error(`connectors.json 格式错误:${(<Error>e).message}`);
}
}
@@ -447,7 +447,7 @@ export function readFileAndParse(fileName: string) {
let readResult = readJsonFile(fileName);
return JSON.parse(readResult);
} catch(e) {
throw new Error(`${fileName}格式错误:${e.message}`);
throw new Error(`${fileName}格式错误:${(<Error>e).message}`);
}
}
@@ -459,7 +459,7 @@ export function readWarJsonFileAndParse() {
let json = JSON.parse(str);
result.push(json);
} catch(e) {
throw new Error(`${name}格式错误:${e.message}`);
throw new Error(`${name}格式错误:${(<Error>e).message}`);
}
}
return result;

View File

@@ -61,4 +61,10 @@ export default class AccountController extends Controller {
const { name, idNum } = ctx.request.body;
ctx.body = await ctx.service.auth.authentication(name, idNum);
}
public async channelLogin() {
const { ctx } = this;
const { channelType, pst, clientId, deviceId, platform, pkgName, serverType, getuiCID } = ctx.request.body;
ctx.body = await ctx.service.auth.channelLogin(channelType, clientId, pst, deviceId, platform, pkgName, serverType, getuiCID);
}
}

View File

@@ -104,7 +104,7 @@ export default class GameController extends Controller {
ctx.body = ctx.service.utils.resResult(STATUS.SUCCESS, { isOK: true });
return;
} catch (e) {
ctx.body = ctx.service.utils.resResult(STATUS.SUCCESS, { isOK: false, err: e.stack });
ctx.body = ctx.service.utils.resResult(STATUS.SUCCESS, { isOK: false, err: (<Error>e).stack });
return;
}
}

View File

@@ -7,6 +7,7 @@ export default (app: Application) => {
router.get('/dev', controller.home.dev);
router.get('/dev/smscode', controller.account.getSmsCode);
router.get('/', controller.home.index);
router.post('/user/channellogin', controller.account.channelLogin);
router.post('/user/devicelogin', controller.account.deviceLogin);
router.post('/user/getsms', controller.account.getSms);
router.post('/user/smslogin', controller.account.smsLogin);

View File

@@ -13,6 +13,8 @@ import { resResult } from '../pubUtils/util';
import { checkTeeanAgerTime } from '../pubUtils/authenticateUtil';
import { authenticate } from '../pubUtils/httpUtil';
import { checkTask } from 'app/pubUtils/taskUtil';
import { getChannelId, loginValidata } from '../pubUtils/sdkUtil';
import { LoginValidateData37 } from 'app/domain/sdk';
/**
* Test Service
@@ -381,4 +383,46 @@ export default class Auth extends Service {
let date = idNum.slice(12, 14);
return `${year}-${month}-${date}`;
}
/**
* 渠道服登录
* @param channelType 渠道类型 37: '37'
* @param clientId
* @param pst
* @param deviceId
* @param platform
* @param pkgName
* @param serverType
* @param getuiCID
* @returns
*/
public async channelLogin(channelType: string, clientId: string, pst: string, deviceId: string, platform: string, pkgName: string, serverType: string, getuiCID: string) {
const ctx = this.ctx;
const ip = ctx.request.ip;
let requestResult = await loginValidata(channelType, clientId, pst)
if(!requestResult) return this.ctx.service.utils.resResult(STATUS.CHANNEL_ERR);
if(requestResult.code != 1) {
return this.ctx.service.utils.resResult(STATUS.VALIDATE_ERR, requestResult);
}
let channelId = getChannelId(channelType, requestResult.data.uid);
const token = ctx.service.utils.generateStr(256);
let user = await UserModel.createOrUpdateChannelUser(channelId, channelType, requestResult.data, token, platform, pkgName, serverType, deviceId, ip);
if (getuiCID) {//更新个推cid
await UserModel.updateGetuiCIDByChannel(channelId, getuiCID);
}
let channelInfo: any = {};
if(channelType == '37') {
channelInfo.uid = (<LoginValidateData37>user.channelInfo).uid;
}
return ctx.service.utils.resResult(STATUS.SUCCESS, {
canLogin: true,
channelId,
token: user.token,
userCode: user.userCode,
channelInfo
});
}
}