Skip to content

Commit 90530dc

Browse files
committed
feat: 登录返回签名
1 parent 58b5e41 commit 90530dc

File tree

7 files changed

+139
-32
lines changed

7 files changed

+139
-32
lines changed

application.dev.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
PORT: 9000
22
PREFIX: api
33

4-
# token过期时间为7天
5-
tokenExpire: 7
4+
# 正常token2小时
5+
tokenExpire: 2
6+
# 刷新过期时间为7天
7+
refreshTokenExpire: 7
68

79
# 默认密码
810
defaultPassword: 123456

src/api/login/login.controller.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
1-
import { Body, Controller, Post } from '@nestjs/common';
1+
import { Body, Controller, Get, Post, Query } from '@nestjs/common';
22
import { LoginDto } from './dto/login.dto';
33
import { LoginService } from './login.service';
44
import { LoginVo } from './vo/login.vo';
55

6-
@Controller('login')
6+
@Controller()
77
export class LoginController {
88
constructor(private readonly loginService: LoginService) {}
99

10-
@Post()
10+
@Post('login')
1111
async loginApi(@Body() req: LoginDto): Promise<LoginVo> {
1212
return await this.loginService.loginApi(req);
1313
}
14+
15+
@Get('refresh')
16+
async refreshTokenApi(@Query('token') token: string): Promise<LoginVo> {
17+
return await this.loginService.refreshTokenApi(token);
18+
}
1419
}

src/api/login/login.service.ts

Lines changed: 76 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
2+
import { ConfigService } from '@nestjs/config';
23
import { InjectRepository } from '@nestjs/typeorm';
34
import { LoggerService } from '@src/plugin/logger/logger.service';
45
import { RedisService } from '@src/plugin/redis/redis.service';
56
import { ToolsService } from '@src/plugin/tools/tools.service';
67
import { Repository, SelectQueryBuilder } from 'typeorm';
78
import { AccountEntity } from '../account/entities/account.entity';
89
import { LoginDto } from './dto/login.dto';
9-
import { LoginVo } from './vo/login.vo';
10-
11-
type findAccountType = Omit<AccountEntity, 'created_at' | 'updated_at'>;
10+
import { LoginAccountVo, LoginTokenDataVo, LoginVo } from './vo/login.vo';
1211

1312
@Injectable()
1413
export class LoginService {
@@ -17,7 +16,8 @@ export class LoginService {
1716
private readonly accountRepository: Repository<AccountEntity>,
1817
private readonly toolsService: ToolsService,
1918
private readonly loggerService: LoggerService,
20-
private readonly redisService: RedisService
19+
private readonly redisService: RedisService,
20+
private readonly configService: ConfigService
2121
) {}
2222

2323
/**
@@ -30,32 +30,15 @@ export class LoginService {
3030
*/
3131
async loginApi(req: LoginDto): Promise<LoginVo> {
3232
const { username, password } = req;
33-
const accountEntity:
34-
| Pick<AccountEntity, 'id' | 'username' | 'status' | 'accountType' | 'password' | 'salt'>
35-
| undefined = await this.queryLoginBuilder
33+
const accountEntity: LoginAccountVo | undefined = await this.queryLoginBuilder
3634
.where('(account.username = :username)', { username: username })
3735
.getRawOne();
3836
if (accountEntity?.id) {
3937
console.log(accountEntity.password, '111', password);
4038
// 判断密码是否正确
4139
const saltPassword = this.toolsService.makePassword(password, accountEntity.salt);
4240
if (Object.is(saltPassword, accountEntity.password)) {
43-
// 生成token存储到token表中并且返回给前端
44-
const token = this.toolsService.uuidToken;
45-
// 根据资源id获取资源信息
46-
this.redisService.set(
47-
token,
48-
{
49-
userInfo: accountEntity, // 用户信息
50-
},
51-
7 * 24 * 60 * 60
52-
);
53-
return {
54-
id: accountEntity.id, // 账号id
55-
username: accountEntity.username, // 用户名
56-
accountType: accountEntity.accountType, // 账号类型:0普通账号,1是主账号,2是超管
57-
token, // 登录的token
58-
};
41+
return await this.generateToken(accountEntity);
5942
} else {
6043
throw new HttpException('账号或密码错误', HttpStatus.OK);
6144
}
@@ -65,15 +48,35 @@ export class LoginService {
6548
}
6649
}
6750

51+
/**
52+
* @Author: 水痕
53+
* @Date: 2023-10-08 08:44:55
54+
* @LastEditors: 水痕
55+
* @Description:
56+
* @param {string} token
57+
* @return {*}
58+
*/
59+
async refreshTokenApi(token: string): Promise<LoginVo> {
60+
// 1.在redis中读取是否有这个token
61+
const redisData = await this.redisService.get(token);
62+
if (redisData) {
63+
const redisDataObj = redisData as unknown as LoginTokenDataVo;
64+
return await this.generateToken(redisDataObj.userInfo);
65+
} else {
66+
throw new HttpException(
67+
JSON.stringify({ code: 10024, message: '你还没登录,请先登录' }),
68+
HttpStatus.OK
69+
);
70+
}
71+
}
6872
/**
6973
* @Author:
7074
* @Date: 2023-10-08 07:52:37
7175
* @LastEditors:
7276
* @Description: 内部使用查询数据
7377
* @return {*}
7478
*/
75-
76-
private get queryLoginBuilder(): SelectQueryBuilder<findAccountType> {
79+
private get queryLoginBuilder(): SelectQueryBuilder<LoginAccountVo> {
7780
return this.accountRepository
7881
.createQueryBuilder('account')
7982
.select('account.id', 'id')
@@ -83,4 +86,52 @@ export class LoginService {
8386
.addSelect('account.password', 'password')
8487
.addSelect('account.salt', 'salt');
8588
}
89+
90+
/**
91+
* @Author: 水痕
92+
* @Date: 2023-10-08 09:07:02
93+
* @LastEditors: 水痕
94+
* @Description: 内部生成token
95+
* @param {LoginAccountVo} accountEntity
96+
* @return {*}
97+
*/
98+
private async generateToken(
99+
accountEntity: LoginAccountVo
100+
): Promise<Promise<Promise<Promise<LoginVo>>>> {
101+
// 生成token存储到token表中并且返回给前端
102+
const tokenExpire: number = this.configService.get('tokenExpire') ?? 2;
103+
const refreshTokenExpire: number = this.configService.get('refreshTokenExpire') ?? 7;
104+
const token = this.toolsService.uuidToken;
105+
const refreshToken = this.toolsService.uuidToken;
106+
const sign = this.toolsService.uuidToken;
107+
// 根据资源id获取资源信息
108+
const redisData: LoginTokenDataVo = {
109+
userInfo: accountEntity, // 用户信息
110+
sign,
111+
};
112+
// 正常token
113+
await this.redisService.set(token, redisData, tokenExpire * 60 * 60);
114+
// 刷新token
115+
await this.redisService.set(refreshToken, redisData, refreshTokenExpire * 24 * 60 * 60);
116+
// 删除redis中历史的token,并且设置新的
117+
const accountTokenKey = this.toolsService.generateLoginTokenKey(accountEntity.id);
118+
const accountRefreshTokenKey = this.toolsService.generateLoginRefreshTokenKey(accountEntity.id);
119+
const accountToken = (await this.redisService.get(accountTokenKey)) as unknown as string;
120+
const accountRefreshToken = (await this.redisService.get(
121+
accountRefreshTokenKey
122+
)) as unknown as string;
123+
console.log(accountToken, accountRefreshToken, '要删除的');
124+
await this.redisService.del(accountToken);
125+
await this.redisService.del(accountRefreshToken);
126+
this.redisService.set(accountTokenKey, token, tokenExpire * 60 * 60);
127+
this.redisService.set(accountRefreshTokenKey, refreshToken, refreshTokenExpire * 24 * 60 * 60);
128+
return {
129+
id: accountEntity.id, // 账号id
130+
username: accountEntity.username, // 用户名
131+
accountType: accountEntity.accountType, // 账号类型:0普通账号,1是主账号,2是超管
132+
token, // 登录的token
133+
refreshToken,
134+
sign,
135+
};
136+
}
86137
}

src/api/login/vo/login.vo.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,20 @@ export class LoginVo {
33
readonly username?: string; // 用户名
44
readonly accountType?: number; // 账号类型:0普通账号,1是主账号,2是超管
55
readonly token?: string; // 登录的token
6+
readonly refreshToken?: string; // 刷新token
7+
readonly sign!: string; // 签名key
8+
}
9+
10+
export class LoginAccountVo {
11+
readonly id!: number; // 账号id
12+
readonly username!: string; // 用户名
13+
readonly accountType!: number; // 账号类型:0普通账号,1是主账号,2是超管
14+
readonly status!: number; // 状态0是正常,1是禁用
15+
readonly password!: string; // 密码
16+
readonly salt!: string; // 密码盐
17+
}
18+
19+
export class LoginTokenDataVo {
20+
readonly userInfo!: LoginAccountVo; // 用户基本信息
21+
readonly sign!: string; // 签名key
622
}

src/constants/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
/**项目前缀 */
22
export const ADMIN_PREFIX = 'admin';
3+
/** redis中存储token前缀 */
4+
export const TOKEN_PREFIX = 'account_login_token';
5+
export const TOKEN_REFRESH_PREFIX = 'account_login_refresh_token';
36

47
export * from './redis.cache';
58
export * from './redis.limit';

src/guard/auth.guard.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,16 @@ export class AuthGuard implements CanActivate {
2626
request.user = result;
2727
return true;
2828
} else {
29-
throw new HttpException('你传递token错误', HttpStatus.FORBIDDEN);
29+
throw new HttpException(
30+
JSON.stringify({ code: 10024, message: '你还没登录,请先登录' }),
31+
HttpStatus.OK
32+
);
3033
}
3134
} else {
32-
throw new HttpException('请传递token', HttpStatus.FORBIDDEN);
35+
throw new HttpException(
36+
JSON.stringify({ code: 10024, message: '你还没登录,请先登录' }),
37+
HttpStatus.OK
38+
);
3339
}
3440
}
3541
}

src/plugin/tools/tools.service.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Injectable } from '@nestjs/common';
22
import { Request } from 'express';
33
import { v4 as uuidv4 } from 'uuid';
44
import { getRandomNum, randomString, strToMd5 } from '@src/utils';
5+
import { TOKEN_PREFIX, TOKEN_REFRESH_PREFIX } from '@src/constants';
56

67
@Injectable()
78
export class ToolsService {
@@ -61,4 +62,27 @@ export class ToolsService {
6162
makePassword(password: string, salt: string): string {
6263
return strToMd5(`${password}_${salt}`);
6364
}
65+
66+
/**
67+
* @Author: 水痕
68+
* @Date: 2023-10-08 09:16:32
69+
* @LastEditors: 水痕
70+
* @Description: 登录token的key
71+
* @param {number} accountId
72+
* @return {*}
73+
*/
74+
generateLoginTokenKey(accountId: number): string {
75+
return `${TOKEN_PREFIX}_${accountId}`;
76+
}
77+
/**
78+
* @Author: 水痕
79+
* @Date: 2023-10-08 09:16:45
80+
* @LastEditors: 水痕
81+
* @Description: 刷新token的key
82+
* @param {number} accountId
83+
* @return {*}
84+
*/
85+
generateLoginRefreshTokenKey(accountId: number): string {
86+
return `${TOKEN_REFRESH_PREFIX}_${accountId}`;
87+
}
6488
}

0 commit comments

Comments
 (0)