import { Config, Inject, Provide } from '@midwayjs/core';
|
import { BaseService, CoolCommException } from '@cool-midway/core';
|
import { InjectEntityModel } from '@midwayjs/typeorm';
|
import { Equal, Repository } from 'typeorm';
|
import { UserInfoEntity } from '../entity/info';
|
import { UserWxService } from './wx';
|
import * as jwt from 'jsonwebtoken';
|
import { UserWxEntity } from '../entity/wx';
|
import { BaseSysLoginService } from '../../base/service/sys/login';
|
import { UserSmsService } from './sms';
|
import { v1 as uuid } from 'uuid';
|
import * as md5 from 'md5';
|
import { PluginService } from '../../plugin/service/info';
|
|
/**
|
* 登录
|
*/
|
@Provide()
|
export class UserLoginService extends BaseService {
|
@InjectEntityModel(UserInfoEntity)
|
userInfoEntity: Repository<UserInfoEntity>;
|
|
@InjectEntityModel(UserWxEntity)
|
userWxEntity: Repository<UserWxEntity>;
|
|
@Inject()
|
userWxService: UserWxService;
|
|
@Config('module.user.jwt')
|
jwtConfig;
|
|
@Inject()
|
baseSysLoginService: BaseSysLoginService;
|
|
@Inject()
|
pluginService: PluginService;
|
|
@Inject()
|
userSmsService: UserSmsService;
|
|
/**
|
* 发送手机验证码
|
* @param phone
|
* @param captchaId
|
* @param code
|
*/
|
async smsCode(phone, captchaId, code) {
|
// 1、检查图片验证码 2、发送短信验证码
|
const check = await this.baseSysLoginService.captchaCheck(captchaId, code);
|
if (!check) {
|
throw new CoolCommException('图片验证码错误');
|
}
|
await this.userSmsService.sendSms(phone);
|
}
|
|
/**
|
* 手机验证码登录
|
* @param phone
|
* @param smsCode
|
*/
|
async phoneVerifyCode(phone, smsCode) {
|
// 1、检查短信验证码 2、登录
|
const check = await this.userSmsService.checkCode(phone, smsCode);
|
if (check) {
|
return await this.phone(phone);
|
} else {
|
throw new CoolCommException('验证码错误');
|
}
|
}
|
|
/**
|
* 小程序手机号登录
|
* @param code
|
* @param encryptedData
|
* @param iv
|
*/
|
async miniPhone(code, encryptedData, iv) {
|
const phone = await this.userWxService.miniPhone(code, encryptedData, iv);
|
if (phone) {
|
return await this.phone(phone);
|
} else {
|
throw new CoolCommException('获得手机号失败,请检查配置');
|
}
|
}
|
|
/**
|
* 手机号一键登录
|
* @param access_token
|
* @param openid
|
*/
|
async uniPhone(access_token, openid, appId) {
|
const instance: any = await this.pluginService.getInstance('uniphone');
|
const phone = await instance.getPhone(access_token, openid, appId);
|
if (phone) {
|
return await this.phone(phone);
|
} else {
|
throw new CoolCommException('获得手机号失败,请检查配置');
|
}
|
}
|
|
/**
|
* 手机登录
|
* @param phone
|
* @returns
|
*/
|
async phone(phone: string) {
|
let user: any = await this.userInfoEntity.findOneBy({
|
phone: Equal(phone),
|
});
|
if (!user) {
|
user = {
|
phone,
|
unionid: phone,
|
loginType: 2,
|
nickName: phone.replace(/^(\d{3})\d{4}(\d{4})$/, '$1****$2'),
|
};
|
await this.userInfoEntity.insert(user);
|
}
|
return this.token({ id: user.id });
|
}
|
|
/**
|
* 公众号登录
|
* @param code
|
*/
|
async mp(code: string) {
|
let wxUserInfo = await this.userWxService.mpUserInfo(code);
|
if (wxUserInfo) {
|
delete wxUserInfo.privilege;
|
wxUserInfo = await this.saveWxInfo(
|
{
|
openid: wxUserInfo.openid,
|
unionid: wxUserInfo.unionid,
|
avatarUrl: wxUserInfo.headimgurl,
|
nickName: wxUserInfo.nickname,
|
gender: wxUserInfo.sex,
|
city: wxUserInfo.city,
|
province: wxUserInfo.province,
|
country: wxUserInfo.country,
|
},
|
1
|
);
|
return this.wxLoginToken(wxUserInfo);
|
} else {
|
throw new Error('微信登录失败');
|
}
|
}
|
|
/**
|
* 微信APP授权登录
|
* @param code
|
*/
|
async wxApp(code: string) {
|
let wxUserInfo = await this.userWxService.appUserInfo(code);
|
if (wxUserInfo) {
|
delete wxUserInfo.privilege;
|
wxUserInfo = await this.saveWxInfo(
|
{
|
openid: wxUserInfo.openid,
|
unionid: wxUserInfo.unionid,
|
avatarUrl: wxUserInfo.headimgurl,
|
nickName: wxUserInfo.nickname,
|
gender: wxUserInfo.sex,
|
city: wxUserInfo.city,
|
province: wxUserInfo.province,
|
country: wxUserInfo.country,
|
},
|
1
|
);
|
return this.wxLoginToken(wxUserInfo);
|
} else {
|
throw new Error('微信登录失败');
|
}
|
}
|
|
/**
|
* 保存微信信息
|
* @param wxUserInfo
|
* @param type
|
* @returns
|
*/
|
async saveWxInfo(wxUserInfo, type) {
|
const find: any = { openid: wxUserInfo.openid };
|
let wxInfo: any = await this.userWxEntity.findOneBy(find);
|
if (wxInfo) {
|
wxUserInfo.id = wxInfo.id;
|
}
|
return this.userWxEntity.save({
|
...wxUserInfo,
|
type,
|
});
|
}
|
|
/**
|
* 小程序登录
|
* @param code
|
* @param encryptedData
|
* @param iv
|
*/
|
async mini(code, encryptedData, iv) {
|
let wxUserInfo = await this.userWxService.miniUserInfo(
|
code,
|
encryptedData,
|
iv
|
);
|
if (wxUserInfo) {
|
// 保存
|
wxUserInfo = await this.saveWxInfo(wxUserInfo, 0);
|
return await this.wxLoginToken(wxUserInfo);
|
}
|
}
|
|
/**
|
* 微信登录 获得token
|
* @param wxUserInfo 微信用户信息
|
* @returns
|
*/
|
async wxLoginToken(wxUserInfo) {
|
const unionid = wxUserInfo.unionid ? wxUserInfo.unionid : wxUserInfo.openid;
|
let userInfo: any = await this.userInfoEntity.findOneBy({ unionid });
|
if (!userInfo) {
|
const file = await this.pluginService.getInstance('upload');
|
const avatarUrl = await file.downAndUpload(
|
wxUserInfo.avatarUrl,
|
uuid() + '.png'
|
);
|
userInfo = {
|
unionid,
|
nickName: wxUserInfo.nickName,
|
avatarUrl,
|
gender: wxUserInfo.gender,
|
loginType: wxUserInfo.type,
|
};
|
await this.userInfoEntity.insert(userInfo);
|
}
|
return this.token({ id: userInfo.id });
|
}
|
|
/**
|
* 刷新token
|
* @param refreshToken
|
*/
|
async refreshToken(refreshToken) {
|
try {
|
const info = jwt.verify(refreshToken, this.jwtConfig.secret);
|
if (!info['isRefresh']) {
|
throw new CoolCommException('token类型非refreshToken');
|
}
|
const userInfo = await this.userInfoEntity.findOneBy({
|
id: info['id'],
|
});
|
return this.token({ id: userInfo.id });
|
} catch (e) {
|
throw new CoolCommException(
|
'刷新token失败,请检查refreshToken是否正确或过期'
|
);
|
}
|
}
|
|
/**
|
* 密码登录
|
* @param phone
|
* @param password
|
*/
|
async password(phone, password) {
|
const user = await this.userInfoEntity.findOneBy({ phone });
|
|
if (user && user.password == md5(password)) {
|
return this.token({
|
id: user.id,
|
});
|
} else {
|
throw new CoolCommException('账号或密码错误');
|
}
|
}
|
|
/**
|
* 获得token
|
* @param info
|
* @returns
|
*/
|
async token(info) {
|
const { expire, refreshExpire } = this.jwtConfig;
|
return {
|
expire,
|
token: await this.generateToken(info),
|
refreshExpire,
|
refreshToken: await this.generateToken(info, true),
|
};
|
}
|
|
/**
|
* 生成token
|
* @param tokenInfo 信息
|
* @param roleIds 角色集合
|
*/
|
async generateToken(info, isRefresh = false) {
|
const { expire, refreshExpire, secret } = this.jwtConfig;
|
const user = await this.userInfoEntity.findOneBy({ id: Equal(info.id) });
|
const tokenInfo = {
|
isRefresh,
|
...info,
|
tenantId: user?.tenantId,
|
};
|
return jwt.sign(tokenInfo, secret, {
|
expiresIn: isRefresh ? refreshExpire : expire,
|
});
|
}
|
}
|