新增用户模块

This commit is contained in:
无风 2023-04-13 18:56:48 +08:00
parent 600e2396c4
commit 3f81cf32be
6 changed files with 328 additions and 1 deletions

View File

@ -4,8 +4,8 @@
"description": "一个项目用COOL就够了",
"private": true,
"dependencies": {
"@cool-midway/core": "^6.0.1",
"@cool-midway/cloud": "^6.0.0",
"@cool-midway/core": "^6.0.1",
"@cool-midway/file": "^6.0.0",
"@cool-midway/iot": "^6.0.0",
"@cool-midway/pay": "^6.0.0",
@ -24,6 +24,8 @@
"@midwayjs/typeorm": "^3.10.7",
"@midwayjs/validate": "^3.10.7",
"@midwayjs/view-ejs": "^3.10.7",
"axios": "^1.3.5",
"@alicloud/pop-core": "^1.7.12",
"cache-manager-fs-hash": "^1.0.0",
"ipip-ipdb": "^0.6.0",
"jsonwebtoken": "^9.0.0",

View File

@ -0,0 +1,40 @@
import { ModuleConfig } from '@cool-midway/core';
/**
*
*/
export default () => {
return {
// 模块名称
name: '用户模块',
// 模块描述
description: 'APP、小程序、公众号等用户',
// 中间件,只对本模块有效
middlewares: [],
// 中间件,全局有效
globalMiddlewares: [],
// 模块加载顺序默认为0值越大越优先加载
order: 0,
// 阿里云短信
sms: {
signName: '',
templateCode: ' ',
accessKeyId: '',
accessKeySecret: '',
// 验证码有效期,单位秒
timeout: 60 * 3,
},
// 微信配置
wx: {
// 小程序
mini: {
appid: 'xxx',
secret: 'xxx',
},
mp: {
appid: 'xxx',
secret: 'xxx',
},
},
} as ModuleConfig;
};

View File

@ -0,0 +1,28 @@
import { BaseEntity } from '@cool-midway/core';
import { Column, Entity, Index } from 'typeorm';
/**
*
*/
@Entity('user_info')
export class UserInfoEntity extends BaseEntity {
@Index()
@Column({ comment: '第三方登录的唯一ID微信、QQ等' })
unionid: string;
@Column({ comment: '头像' })
avatarUrl: string;
@Column({ comment: '昵称' })
nickName: string;
@Index({ unique: true })
@Column({ comment: '手机号' })
phone: string;
@Column({ comment: '性别 0-未知 1-男 2-女', default: 0 })
gender: number;
@Column({ comment: '状态 0-正常 1-禁用', default: 0 })
status: number;
}

View File

@ -0,0 +1,29 @@
import { BaseEntity } from '@cool-midway/core';
import { Column, Entity } from 'typeorm';
/**
*
*/
@Entity('user_wx')
export class UserWxEntity extends BaseEntity {
@Column({ comment: '头像', nullable: true })
avatarUrl: number;
@Column({ comment: '昵称', nullable: true })
nickName: string;
@Column({ comment: '性别 0-未知 1-男 2-女', default: 0 })
gender: number;
@Column({ comment: '语言' })
language: number;
@Column({ comment: '城市' })
city: number;
@Column({ comment: '省份' })
province: number;
@Column({ comment: '国家' })
country: number;
}

View File

@ -0,0 +1,61 @@
import { Provide, Config, Inject } from '@midwayjs/decorator';
import { BaseService } from '@cool-midway/core';
import * as _ from 'lodash';
import * as Core from '@alicloud/pop-core';
import { CacheManager } from '@midwayjs/cache';
/**
*
*/
@Provide()
export class UserSmsService extends BaseService {
// 获得模块的配置信息
@Config('module.user.sms')
config;
@Inject()
cacheManager: CacheManager;
/**
*
* @param phone
*/
async sendSms(phone) {
const TemplateParam = { code: _.random(1000, 9999) };
await this.send(phone, TemplateParam);
this.cacheManager.set(
`sms:${phone}`,
TemplateParam.code,
this.config.sms.timeout
);
}
/**
*
* @param phone
* @param templateCode
* @param template
*/
async send(phone, TemplateParam) {
const { signName, accessKeyId, accessKeySecret, templateCode } =
this.config;
const client = new Core({
accessKeyId,
accessKeySecret,
endpoint: 'https://dysmsapi.aliyuncs.com',
// endpoint: 'https://cs.cn-hangzhou.aliyuncs.com',
apiVersion: '2017-05-25',
// apiVersion: '2018-04-18',
});
const params = {
RegionId: 'cn-shanghai',
PhoneNumbers: phone,
signName,
templateCode,
TemplateParam: JSON.stringify(TemplateParam),
};
return await client.request('SendSms', params, {
method: 'POST',
});
}
}

View File

@ -0,0 +1,167 @@
import { Config, Provide } from '@midwayjs/decorator';
import { BaseService, CoolCommException } from '@cool-midway/core';
import axios from 'axios';
import * as crypto from 'crypto';
/**
*
*/
@Provide()
export class UserWxService extends BaseService {
@Config('module.user')
config;
/**
*
* @param code
*/
async mpUserInfo(code) {
const token = await this.openOrMpToken(code, this.config.wx.mp);
return await this.openOrMpUserInfo(token);
}
/**
* token code
* @param appid
* @param secret
*/
public async getWxToken(type = 'mp') {
//@ts-ignore
const conf = this.config.wx[type];
return await axios.get('https://api.weixin.qq.com/cgi-bin/token', {
params: {
grant_type: 'client_credential',
appid: conf.appid,
secret: conf.secret,
},
});
}
/**
*
* @param token
*/
async openOrMpUserInfo(token) {
return await axios
.get('https://api.weixin.qq.com/sns/userinfo', {
params: {
access_token: token.access_token,
openid: token.openid,
lang: 'zh_CN',
},
})
.then(res => {
return res.data;
});
}
/**
* token嗯
* @param code
* @param conf
*/
async openOrMpToken(code, conf) {
const result = await axios.get(
'https://api.weixin.qq.com/sns/oauth2/access_token',
{
params: {
appid: conf.appid,
secret: conf.secret,
code,
grant_type: 'authorization_code',
},
}
);
return result.data;
}
/**
* session
* @param code code
* @param conf
*/
async miniSession(code) {
const { appid, secret } = this.config.wx.mini;
const result = await axios.get(
'https://api.weixin.qq.com/sns/jscode2session',
{
params: {
appid,
secret,
js_code: code,
grant_type: 'authorization_code',
},
}
);
return result.data;
}
/**
*
* @param code
* @param encryptedData
* @param iv
*/
async miniUserInfo(code, encryptedData, iv) {
const session = await this.miniSession(code);
if (session.errcode) {
throw new CoolCommException('登录失败,请重试');
}
const info: any = await this.miniDecryptData(
encryptedData,
iv,
session.session_key
);
if (info) {
delete info['watermark'];
return {
...info,
openid: session['openid'],
unionid: session['unionid'],
};
}
return null;
}
/**
*
* @param code
* @param encryptedData
* @param iv
*/
async miniPhone(code, encryptedData, iv) {
const session = await this.miniSession(code);
if (session.errcode) {
throw new CoolCommException('获取手机号失败,请刷新重试');
}
return await this.miniDecryptData(encryptedData, iv, session.session_key);
}
/**
*
* @param encryptedData
* @param iv
* @param sessionKey
*/
async miniDecryptData(encryptedData, iv, sessionKey) {
sessionKey = Buffer.from(sessionKey, 'base64');
encryptedData = Buffer.from(encryptedData, 'base64');
iv = Buffer.from(iv, 'base64');
try {
// 解密
const decipher = crypto.createDecipheriv('aes-128-cbc', sessionKey, iv);
// 设置自动 padding 为 true删除填充补位
decipher.setAutoPadding(true);
// @ts-ignore
let decoded = decipher.update(encryptedData, 'binary', 'utf8');
// @ts-ignore
decoded += decipher.final('utf8');
// @ts-ignore
decoded = JSON.parse(decoded);
return decoded;
} catch (err) {
throw new CoolCommException('获得信息失败');
}
}
}