Skip to content

Commit c2e428f

Browse files
committed
feat: 登录生成token的问题
1 parent fe539a1 commit c2e428f

File tree

4 files changed

+138
-37
lines changed

4 files changed

+138
-37
lines changed

src/config/admin.config.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,6 @@ export default {
22
adminPath: 'admin',
33
defaultAccount: 'admin',
44
defaultPassword: '123456',
5+
/**token失效时间为1天 */
6+
tokenExpire: 1,
57
};

src/modules/admin/system/account/entities/account.token.entity.ts

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { PlatformEnum } from '@src/enums';
12
import { SharedEntity } from '@src/modules/shared/entities/shared.entity';
23
import { Column, Entity } from 'typeorm';
34

@@ -34,20 +35,38 @@ export class AccountTokenEntity extends SharedEntity {
3435
@Column({
3536
type: 'varchar',
3637
nullable: true,
37-
length: 110,
38+
length: 11,
3839
name: 'mobile',
3940
comment: '手机号码',
4041
})
4142
mobile: string;
4243

4344
@Column({
4445
type: 'varchar',
45-
nullable: false,
46-
length: 30,
46+
nullable: true,
47+
length: 50,
48+
name: 'email',
49+
comment: '邮箱',
50+
})
51+
email: string;
52+
53+
@Column({
54+
type: 'tinyint',
55+
nullable: true,
4756
name: 'platform',
48-
comment: '平台',
57+
default: 0,
58+
comment: '平台:0表示普通用户(没权限),1表示为运营管理,2表示入住商家',
59+
})
60+
platform: PlatformEnum;
61+
62+
@Column({
63+
type: 'tinyint',
64+
nullable: false,
65+
default: 0,
66+
name: 'is_super',
67+
comment: '是否为超级管理员1表示是,0表示不是',
4968
})
50-
platform: string;
69+
isSuper: number;
5170

5271
@Column({
5372
type: 'timestamp',

src/modules/admin/system/account/services/login/login.service.ts

Lines changed: 111 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,35 @@ import { Injectable, HttpException, HttpStatus, Logger } from '@nestjs/common';
22
import { LoginDto } from '../../controllers/login/dto/login.dto';
33
import { AccountEntity } from '../../entities/account.entity';
44
import { InjectRepository } from '@nestjs/typeorm';
5-
import { Repository, getConnection } from 'typeorm';
5+
import { Repository, getConnection, SelectQueryBuilder } from 'typeorm';
66
import { ToolsService } from '@src/modules/shared/services/tools/tools.service';
77
import { isMobilePhone, isEmail } from 'class-validator';
88
import { AccountLastLoginEntity } from '../../entities/account.last.login.entity';
99
import { LoginVo } from '../../controllers/login/vo/login.vo';
10+
import { AccountTokenEntity } from '../../entities/account.token.entity';
11+
import { ConfigService, InjectConfig } from 'nestjs-config';
12+
import moment from 'moment';
13+
import { usernameReg } from '@src/constants';
1014

15+
interface IAccount {
16+
id: number;
17+
username: string;
18+
email: string;
19+
mobile: string;
20+
isSuper: number;
21+
platform: number;
22+
}
1123
@Injectable()
1224
export class LoginService {
1325
private logger: Logger = new Logger(LoginService.name);
1426
constructor(
15-
@InjectRepository(AccountEntity)
16-
private readonly accountRepository: Repository<AccountEntity>,
1727
@InjectRepository(AccountLastLoginEntity)
1828
private readonly accountLastLoginRepository: Repository<AccountLastLoginEntity>,
29+
@InjectRepository(AccountTokenEntity)
30+
private readonly accountTokenRepository: Repository<AccountTokenEntity>,
1931
private readonly toolsService: ToolsService,
32+
@InjectConfig()
33+
private readonly configService: ConfigService,
2034
) {}
2135

2236
/**
@@ -31,44 +45,75 @@ export class LoginService {
3145
async adminLogin(loginDto: LoginDto, ipAddress: string): Promise<LoginVo> {
3246
try {
3347
const { username, password } = loginDto;
34-
let sqlPassword: string | undefined;
35-
let findAccount: AccountEntity | undefined;
48+
type TypeAccountFindResult = Extract<AccountEntity, IAccount> | undefined;
49+
let findAccount: TypeAccountFindResult;
50+
const queryBuilder = this.queryLoginBuilder;
51+
// 根据手机号码查询
3652
if (isMobilePhone(username, 'zh-CN')) {
37-
const findResult: Pick<AccountEntity, 'password'> | undefined = await getConnection()
38-
.createQueryBuilder(AccountEntity, 'account')
39-
.select([])
40-
.addSelect('account.password', 'password')
53+
findAccount = await queryBuilder
4154
.where('(account.mobile = :mobile)', { mobile: username })
4255
.getRawOne();
43-
sqlPassword = findResult?.password;
44-
findAccount = await this.accountRepository.findOne({ where: { mobile: username } });
4556
} else if (isEmail(username)) {
46-
const findResult: Pick<AccountEntity, 'password'> | undefined = await getConnection()
47-
.createQueryBuilder(AccountEntity, 'account')
48-
.select([])
49-
.addSelect('account.password', 'password')
57+
// 根据邮箱查询
58+
findAccount = await queryBuilder
5059
.where('(account.email = :email)', { email: username })
5160
.getRawOne();
52-
sqlPassword = findResult?.password;
53-
findAccount = await this.accountRepository.findOne({ where: { email: username } });
5461
} else {
55-
const findResult: Pick<AccountEntity, 'password'> | undefined = await getConnection()
56-
.createQueryBuilder(AccountEntity, 'account')
57-
.select([])
58-
.addSelect('account.password', 'password')
62+
// 用户名查询
63+
findAccount = await queryBuilder
5964
.where('(account.username = :username)', { username })
6065
.getRawOne();
61-
sqlPassword = findResult?.password;
62-
findAccount = await this.accountRepository.findOne({ where: { username } });
6366
}
64-
if (sqlPassword && this.toolsService.checkPassword(password, sqlPassword) && findAccount) {
67+
if (
68+
findAccount &&
69+
findAccount.password &&
70+
this.toolsService.checkPassword(password, findAccount.password)
71+
) {
72+
// 记录最后登录时间和ip地址
6573
const lastLogin = this.accountLastLoginRepository.create({
6674
accountId: findAccount.id,
6775
lastLoginIp: ipAddress,
6876
});
6977
await this.accountLastLoginRepository.save(lastLogin);
7078
this.logger.log('当前用户', findAccount);
71-
return Object.assign(findAccount, { token: this.toolsService.generateToken(findAccount) });
79+
// 生成token存储到token表中并且返回给前端
80+
const token = this.toolsService.uuidToken;
81+
const { id, username, email, mobile, isSuper, platform } =
82+
this.filterAccountField(findAccount);
83+
const tokenExpire: number = this.configService.get('admin.tokenExpire');
84+
const accountToken = {
85+
userId: id,
86+
username,
87+
email,
88+
mobile,
89+
isSuper,
90+
platform,
91+
token,
92+
// 设置token失效时间
93+
expireTime: moment().add(tokenExpire, 'day').format('YYYY-MM-DD HH:mm:ss'),
94+
};
95+
// 先判断之前是否有记录,有记录就更新,没记录就创建
96+
const accountTokenResult: Pick<AccountTokenEntity, 'id'> | undefined =
97+
await this.accountTokenRepository.findOne({
98+
where: { userId: id },
99+
select: ['id'],
100+
});
101+
if (accountTokenResult?.id) {
102+
await this.accountTokenRepository.update({ id: accountTokenResult.id }, accountToken);
103+
} else {
104+
const accountTokenSave: AccountTokenEntity =
105+
this.accountTokenRepository.create(accountToken);
106+
await this.accountTokenRepository.save(accountTokenSave);
107+
}
108+
return {
109+
token,
110+
id,
111+
username,
112+
email,
113+
mobile,
114+
isSuper,
115+
platform,
116+
};
72117
} else {
73118
throw new HttpException('用户名或密码错误', HttpStatus.OK);
74119
}
@@ -77,4 +122,45 @@ export class LoginService {
77122
throw new HttpException('用户名或密码错误', HttpStatus.OK);
78123
}
79124
}
125+
126+
/**
127+
* @Author: 水痕
128+
* @Date: 2021-07-26 09:07:15
129+
* @LastEditors: 水痕
130+
* @Description: 公共的查询部分
131+
* @param {*}
132+
* @return {*}
133+
*/
134+
private get queryLoginBuilder(): SelectQueryBuilder<AccountEntity> {
135+
return getConnection()
136+
.createQueryBuilder(AccountEntity, 'account')
137+
.select('account.id', 'id')
138+
.addSelect('account.username', 'username')
139+
.addSelect('account.mobile', 'mobile')
140+
.addSelect('account.email', 'email')
141+
.addSelect('account.platform', 'platform')
142+
.addSelect('account.isSuper', 'isSuper')
143+
.addSelect('account.password', 'password');
144+
}
145+
146+
/**
147+
* @Author: 水痕
148+
* @Date: 2021-07-26 10:15:17
149+
* @LastEditors: 水痕
150+
* @Description: 过来字段
151+
* @param {IAccount} accountInfo
152+
* @return {*}
153+
*/
154+
private filterAccountField(accountInfo: IAccount): IAccount {
155+
const { username, mobile, email } = accountInfo;
156+
const _mobile = isMobilePhone(mobile, 'zh-CN') ? mobile : '';
157+
const _email = isEmail(email) ? email : '';
158+
const _username = usernameReg.test(username) ? username : '';
159+
return {
160+
...accountInfo,
161+
username: _username,
162+
mobile: _mobile,
163+
email: _email,
164+
};
165+
}
80166
}

src/utils/date.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,8 @@ import moment from 'moment';
99
* @Date: 2019-07-31 15:27:39
1010
*/
1111
export const formatDate = (dateNum: string | number, isDue = false): string => {
12-
if (!dateNum) {
13-
return '';
14-
}
15-
// if (!/^\d+$/.test(dateNum.toString())) {
16-
// throw new TypeError(`${dateNum}传递的数据格式化错误`);
17-
// }
1812
if (isDue) {
19-
return moment(dateNum).format('YYYY-MM-DD');
13+
return moment(dateNum).format('YYYY-MM-DD HH:mm:ss');
2014
} else {
2115
return moment(dateNum).format('YYYY-MM-DD HH:mm:ss');
2216
}

0 commit comments

Comments
 (0)