mirror of
https://github.com/cool-team-official/cool-admin-midway.git
synced 2026-01-07 20:18:12 +00:00
308 lines
7.5 KiB
TypeScript
308 lines
7.5 KiB
TypeScript
import { Config, Inject, Provide } from '@midwayjs/decorator';
|
||
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 tokenInfo = {
|
||
isRefresh,
|
||
...info,
|
||
};
|
||
return jwt.sign(tokenInfo, secret, {
|
||
expiresIn: isRefresh ? refreshExpire : expire,
|
||
});
|
||
}
|
||
}
|