mirror of
https://github.com/cool-team-official/cool-admin-midway.git
synced 2024-11-01 22:20:30 +08:00
完善登录
This commit is contained in:
parent
3f81cf32be
commit
c4b1de03f6
@ -36,5 +36,14 @@ export default () => {
|
|||||||
secret: 'xxx',
|
secret: 'xxx',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
// jwt
|
||||||
|
jwt: {
|
||||||
|
// token 过期时间,单位秒
|
||||||
|
expire: 60 * 60 * 2,
|
||||||
|
// 刷新token 过期时间,单位秒
|
||||||
|
refreshExpire: 60 * 60 * 24 * 30,
|
||||||
|
// jwt 秘钥
|
||||||
|
secret: '093243e6ce8',
|
||||||
|
},
|
||||||
} as ModuleConfig;
|
} as ModuleConfig;
|
||||||
};
|
};
|
||||||
|
11
src/modules/user/controller/admin/info.ts
Normal file
11
src/modules/user/controller/admin/info.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { CoolController, BaseController } from '@cool-midway/core';
|
||||||
|
import { UserInfoEntity } from '../../entity/info';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户信息
|
||||||
|
*/
|
||||||
|
@CoolController({
|
||||||
|
api: ['add', 'delete', 'update', 'info', 'list', 'page'],
|
||||||
|
entity: UserInfoEntity,
|
||||||
|
})
|
||||||
|
export class AdminUserInfoController extends BaseController {}
|
50
src/modules/user/controller/app/login.ts
Normal file
50
src/modules/user/controller/app/login.ts
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import { CoolController, BaseController } from '@cool-midway/core';
|
||||||
|
import { Body, Get, Inject, Post, Query } from '@midwayjs/core';
|
||||||
|
import { UserLoginService } from '../../service/login';
|
||||||
|
import { BaseSysLoginService } from '../../../base/service/sys/login';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登录
|
||||||
|
*/
|
||||||
|
@CoolController()
|
||||||
|
export class AppUserLoginController extends BaseController {
|
||||||
|
@Inject()
|
||||||
|
userLoginService: UserLoginService;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
baseSysLoginService: BaseSysLoginService;
|
||||||
|
|
||||||
|
@Post('/mini', { summary: '小程序登录' })
|
||||||
|
async miniLogin(@Body() body) {
|
||||||
|
const { code, encryptedData, iv } = body;
|
||||||
|
return this.ok(await this.userLoginService.mini(code, encryptedData, iv));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post('/mp', { summary: '公众号登录' })
|
||||||
|
async mp(@Body('code') code: string) {
|
||||||
|
return this.ok(await this.userLoginService.mp(code));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post('/phone', { summary: '手机号登录' })
|
||||||
|
async phone(@Body('phone') phone: string, @Body('smsCode') smsCode: string) {
|
||||||
|
return this.ok(await this.userLoginService.phone(phone, smsCode));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get('/captcha', { summary: '图片验证码' })
|
||||||
|
async captcha(
|
||||||
|
@Query('type') type: string,
|
||||||
|
@Query('width') width: number,
|
||||||
|
@Query('height') height: number
|
||||||
|
) {
|
||||||
|
return this.ok(await this.baseSysLoginService.captcha(type, width, height));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post('/smsCode', { summary: '验证码' })
|
||||||
|
async smsCode(
|
||||||
|
@Body('phone') phone: string,
|
||||||
|
@Body('captchaId') captchaId: string,
|
||||||
|
@Body('code') code: string
|
||||||
|
) {
|
||||||
|
return this.ok();
|
||||||
|
}
|
||||||
|
}
|
@ -6,23 +6,26 @@ import { Column, Entity, Index } from 'typeorm';
|
|||||||
*/
|
*/
|
||||||
@Entity('user_info')
|
@Entity('user_info')
|
||||||
export class UserInfoEntity extends BaseEntity {
|
export class UserInfoEntity extends BaseEntity {
|
||||||
@Index()
|
@Index({ unique: true })
|
||||||
@Column({ comment: '第三方登录的唯一ID,如:微信、QQ等' })
|
@Column({ comment: '登录唯一ID', nullable: true })
|
||||||
unionid: string;
|
unionid: string;
|
||||||
|
|
||||||
@Column({ comment: '头像' })
|
@Column({ comment: '头像', nullable: true })
|
||||||
avatarUrl: string;
|
avatarUrl: string;
|
||||||
|
|
||||||
@Column({ comment: '昵称' })
|
@Column({ comment: '昵称', nullable: true })
|
||||||
nickName: string;
|
nickName: string;
|
||||||
|
|
||||||
@Index({ unique: true })
|
@Index({ unique: true })
|
||||||
@Column({ comment: '手机号' })
|
@Column({ comment: '手机号', nullable: true })
|
||||||
phone: string;
|
phone: string;
|
||||||
|
|
||||||
@Column({ comment: '性别 0-未知 1-男 2-女', default: 0 })
|
@Column({ comment: '性别 0-未知 1-男 2-女', default: 0 })
|
||||||
gender: number;
|
gender: number;
|
||||||
|
|
||||||
@Column({ comment: '状态 0-正常 1-禁用', default: 0 })
|
@Column({ comment: '状态 0-禁用 1-正常', default: 1 })
|
||||||
status: number;
|
status: number;
|
||||||
|
|
||||||
|
@Column({ comment: '登录方式 0-小程序 1-公众号 2-H5', default: 0 })
|
||||||
|
loginType: number;
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,19 @@
|
|||||||
import { BaseEntity } from '@cool-midway/core';
|
import { BaseEntity } from '@cool-midway/core';
|
||||||
import { Column, Entity } from 'typeorm';
|
import { Column, Entity, Index } from 'typeorm';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 微信用户
|
* 微信用户
|
||||||
*/
|
*/
|
||||||
@Entity('user_wx')
|
@Entity('user_wx')
|
||||||
export class UserWxEntity extends BaseEntity {
|
export class UserWxEntity extends BaseEntity {
|
||||||
|
@Index()
|
||||||
|
@Column({ comment: '微信unionid', nullable: true })
|
||||||
|
unionid: string;
|
||||||
|
|
||||||
|
@Index()
|
||||||
|
@Column({ comment: '微信openid' })
|
||||||
|
openid: string;
|
||||||
|
|
||||||
@Column({ comment: '头像', nullable: true })
|
@Column({ comment: '头像', nullable: true })
|
||||||
avatarUrl: number;
|
avatarUrl: number;
|
||||||
|
|
||||||
@ -15,15 +23,15 @@ export class UserWxEntity extends BaseEntity {
|
|||||||
@Column({ comment: '性别 0-未知 1-男 2-女', default: 0 })
|
@Column({ comment: '性别 0-未知 1-男 2-女', default: 0 })
|
||||||
gender: number;
|
gender: number;
|
||||||
|
|
||||||
@Column({ comment: '语言' })
|
@Column({ comment: '语言', nullable: true })
|
||||||
language: number;
|
language: number;
|
||||||
|
|
||||||
@Column({ comment: '城市' })
|
@Column({ comment: '城市', nullable: true })
|
||||||
city: number;
|
city: number;
|
||||||
|
|
||||||
@Column({ comment: '省份' })
|
@Column({ comment: '省份', nullable: true })
|
||||||
province: number;
|
province: number;
|
||||||
|
|
||||||
@Column({ comment: '国家' })
|
@Column({ comment: '国家', nullable: true })
|
||||||
country: number;
|
country: number;
|
||||||
}
|
}
|
||||||
|
192
src/modules/user/service/login.ts
Normal file
192
src/modules/user/service/login.ts
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
import { Config, Inject, Provide } from '@midwayjs/decorator';
|
||||||
|
import { BaseService, CoolCommException } from '@cool-midway/core';
|
||||||
|
import { InjectEntityModel } from '@midwayjs/typeorm';
|
||||||
|
import { Repository } from 'typeorm';
|
||||||
|
import { UserInfoEntity } from '../entity/info';
|
||||||
|
import { UserWxService } from './wx';
|
||||||
|
import * as jwt from 'jsonwebtoken';
|
||||||
|
import { UserWxEntity } from '../entity/wx';
|
||||||
|
import { CoolFile } from '@cool-midway/file';
|
||||||
|
import { BaseSysLoginService } from '../../base/service/sys/login';
|
||||||
|
import { UserSmsService } from './sms';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登录
|
||||||
|
*/
|
||||||
|
@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()
|
||||||
|
file: CoolFile;
|
||||||
|
|
||||||
|
@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('图片验证码错误');
|
||||||
|
}
|
||||||
|
this.userSmsService.sendSms(phone);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手机登录
|
||||||
|
* @param phone
|
||||||
|
* @param smsCode
|
||||||
|
*/
|
||||||
|
async phone(phone, smsCode) {
|
||||||
|
// 1、检查短信验证码 2、登录
|
||||||
|
const check = await this.userSmsService.checkCode(phone, smsCode);
|
||||||
|
if (check) {
|
||||||
|
let user: any = await this.userInfoEntity.findOneBy({ phone });
|
||||||
|
if (!user) {
|
||||||
|
user = { phone, unionid: phone, loginType: 2 };
|
||||||
|
await this.userInfoEntity.insert(user);
|
||||||
|
}
|
||||||
|
return this.token({ userId: 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,
|
||||||
|
});
|
||||||
|
return this.wxLoginToken(wxUserInfo);
|
||||||
|
} else {
|
||||||
|
throw new Error('微信登录失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存微信信息
|
||||||
|
* @param wxUserInfo
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async saveWxInfo(wxUserInfo) {
|
||||||
|
const find: any = {};
|
||||||
|
if (wxUserInfo.unionid) {
|
||||||
|
find.unionid = wxUserInfo.unionid;
|
||||||
|
}
|
||||||
|
if (wxUserInfo.openid) {
|
||||||
|
find.openid = wxUserInfo.openid;
|
||||||
|
}
|
||||||
|
let wxInfo: any = await this.userWxEntity.findOneBy(find);
|
||||||
|
if (wxInfo) {
|
||||||
|
delete wxUserInfo.avatarUrl;
|
||||||
|
wxUserInfo.id = wxInfo.id;
|
||||||
|
} else {
|
||||||
|
// 微信的链接会失效,需要保存到本地
|
||||||
|
wxUserInfo.avatarUrl = await this.file.downAndUpload(
|
||||||
|
wxUserInfo.avatarUrl
|
||||||
|
);
|
||||||
|
}
|
||||||
|
await this.userWxEntity.save(wxUserInfo);
|
||||||
|
return wxUserInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 小程序登录
|
||||||
|
* @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);
|
||||||
|
return 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) {
|
||||||
|
userInfo = {
|
||||||
|
unionid,
|
||||||
|
nickName: wxUserInfo.nickName,
|
||||||
|
avatarUrl: wxUserInfo.avatarUrl,
|
||||||
|
gender: wxUserInfo.gender,
|
||||||
|
};
|
||||||
|
await this.userInfoEntity.insert(userInfo);
|
||||||
|
return this.token({ userId: userInfo.id });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得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,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -30,6 +30,20 @@ export class UserSmsService extends BaseService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证验证码
|
||||||
|
* @param phone
|
||||||
|
* @param code
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async checkCode(phone, code) {
|
||||||
|
const cacheCode = await this.cacheManager.get(`sms:${phone}`);
|
||||||
|
if (cacheCode === code) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 发送短信
|
* 发送短信
|
||||||
* @param phone
|
* @param phone
|
||||||
|
Loading…
Reference in New Issue
Block a user