Skip to content

Commit 160536e

Browse files
committed
feat: 接口权限
1 parent c06aa98 commit 160536e

File tree

8 files changed

+119
-13
lines changed

8 files changed

+119
-13
lines changed

src/api/login/login.module.ts

+9-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ import { RouterModule } from '@nestjs/core';
33
import { TypeOrmModule } from '@nestjs/typeorm';
44
import { ADMIN_PREFIX } from '@src/constants';
55
import { AccountEntity } from '../account/entities/account.entity';
6+
import { AccountRoleEntity } from '../accountRole/entities/account.role.entity';
7+
import { ResourcesEntity } from '../resources/entities/resources.entity';
8+
import { RoleResourcesEntity } from '../roleResources/entities/role.resources.entity';
69
import { LoginController } from './login.controller';
710
import { LoginService } from './login.service';
811

@@ -14,7 +17,12 @@ import { LoginService } from './login.service';
1417
module: LoginModule,
1518
},
1619
]),
17-
TypeOrmModule.forFeature([AccountEntity]),
20+
TypeOrmModule.forFeature([
21+
AccountEntity,
22+
AccountRoleEntity,
23+
RoleResourcesEntity,
24+
ResourcesEntity,
25+
]),
1826
],
1927
controllers: [LoginController],
2028
providers: [LoginService],

src/api/login/login.service.ts

+41-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
22
import { ConfigService } from '@nestjs/config';
33
import { InjectRepository } from '@nestjs/typeorm';
4+
import { ResourcesTypeEnum } from '@src/enums/resources.type.enum';
45
import { LoggerService } from '@src/plugin/logger/logger.service';
56
import { RedisService } from '@src/plugin/redis/redis.service';
67
import { ToolsService } from '@src/plugin/tools/tools.service';
7-
import { Repository, SelectQueryBuilder } from 'typeorm';
8+
import { In, Repository, SelectQueryBuilder } from 'typeorm';
89
import { AccountEntity } from '../account/entities/account.entity';
10+
import { AccountRoleEntity } from '../accountRole/entities/account.role.entity';
11+
import { ResourcesEntity } from '../resources/entities/resources.entity';
12+
import { RoleResourcesEntity } from '../roleResources/entities/role.resources.entity';
913
import { LoginDto } from './dto/login.dto';
1014
import { LoginAccountVo, LoginTokenDataVo, LoginVo } from './vo/login.vo';
1115

@@ -14,6 +18,12 @@ export class LoginService {
1418
constructor(
1519
@InjectRepository(AccountEntity)
1620
private readonly accountRepository: Repository<AccountEntity>,
21+
@InjectRepository(AccountRoleEntity)
22+
private readonly accountRoleRepository: Repository<AccountRoleEntity>,
23+
@InjectRepository(RoleResourcesEntity)
24+
private readonly roleResourcesRepository: Repository<RoleResourcesEntity>,
25+
@InjectRepository(ResourcesEntity)
26+
private readonly resourcesRepository: Repository<ResourcesEntity>,
1727
private readonly toolsService: ToolsService,
1828
private readonly loggerService: LoggerService,
1929
private readonly redisService: RedisService,
@@ -106,9 +116,39 @@ export class LoginService {
106116
const token = this.toolsService.uuidToken;
107117
const refreshToken = this.toolsService.uuidToken;
108118
const sign = this.toolsService.uuidToken;
119+
// 根据当前用户获取授权的按钮权限
120+
const accountRoleEntityList: Pick<AccountRoleEntity, 'roleId'>[] =
121+
await this.accountRoleRepository.find({
122+
where: {
123+
accountId: accountEntity.id,
124+
},
125+
select: ['roleId'],
126+
});
127+
const roleIdList = accountRoleEntityList.map((item) => item.roleId);
128+
const roleResourcesList: Pick<RoleResourcesEntity, 'resourcesId'>[] =
129+
await this.roleResourcesRepository.find({
130+
where: {
131+
type: 1,
132+
roleId: In(roleIdList),
133+
},
134+
select: ['resourcesId'],
135+
});
136+
const resourcesIdList = roleResourcesList.map((item) => item.resourcesId);
137+
// 查询全部的资源
138+
const resourcesEntity = await this.resourcesRepository.find({
139+
where: {
140+
id: In(resourcesIdList),
141+
},
142+
select: ['url', 'method', 'title', 'resourcesType'],
143+
});
144+
console.log(resourcesEntity, '1111');
145+
const resources = resourcesEntity.filter((item) => item.resourcesType == ResourcesTypeEnum.API);
146+
console.log(resources, '全部的资源');
147+
// 根据角色idList去查询授权的按钮
109148
// 根据资源id获取资源信息
110149
const redisData: LoginTokenDataVo = {
111150
userInfo: accountEntity, // 用户信息
151+
authApi: resources, // 授权的api接口
112152
sign,
113153
};
114154
// 正常token

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

+3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { ResourcesEntity } from '@src/api/resources/entities/resources.entity';
2+
13
export class LoginVo {
24
readonly id!: number; // 账号id
35
readonly username?: string; // 用户名
@@ -20,4 +22,5 @@ export class LoginAccountVo {
2022
export class LoginTokenDataVo {
2123
readonly userInfo!: LoginAccountVo; // 用户基本信息
2224
readonly sign!: string; // 签名key
25+
readonly authApi!: Pick<ResourcesEntity, 'id' | 'title' | 'method' | 'resourcesType' | 'url'>[];
2326
}

src/api/menus/vo/menus.vo.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ export class MenusVo {
77
method!: MethodEnum; // 接口的请求方式
88
icon!: string; // 菜单小图标
99
sort!: number; // 菜单,或接口排序
10-
type!: number; // 0目录,1菜单,2接口
10+
resourcesType!: number; // 0目录,1菜单,2接口
1111
parentId!: number; // 上一级id
1212
status!: number; // 状态:0是正常,1是禁止
1313
}

src/api/resources/entities/resources.entity.ts

-9
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,6 @@ export class ResourcesEntity extends SharedEntity {
4747
})
4848
resourcesType!: number;
4949

50-
@Column({
51-
type: 'tinyint',
52-
name: 'type',
53-
nullable: true,
54-
default: '0',
55-
comment: '是否为模块:0,菜单:1,按钮(接口):2',
56-
})
57-
type!: number;
58-
5950
@Column({
6051
type: 'int',
6152
name: 'parent_id',

src/app.module.ts

+10-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@ import { ConfigModule, ConfigService } from '@nestjs/config';
33
import { APP_FILTER, APP_INTERCEPTOR, APP_PIPE } from '@nestjs/core';
44
import { TypeOrmModule } from '@nestjs/typeorm';
55
import { HttpExceptionFilter } from './filters/http-exception.filter';
6-
import { LoggerInterceptor, RedisCacheInterceptor, RedisLimitInterceptor } from './interceptors';
6+
import {
7+
LoggerInterceptor,
8+
RedisCacheInterceptor,
9+
RedisLimitInterceptor,
10+
ApiInterceptor,
11+
} from './interceptors';
712
import { TransformInterceptor } from './interceptors/transform.interceptor';
813
import { ValidationPipe } from './pipe/validation.pipe';
914
import { getConfig } from './utils';
@@ -70,6 +75,10 @@ import { PluginModule } from './plugin/plugin.module';
7075
provide: APP_INTERCEPTOR,
7176
useClass: TransformInterceptor,
7277
},
78+
{
79+
provide: APP_INTERCEPTOR,
80+
useClass: ApiInterceptor,
81+
},
7382
// 全局使用管道(数据校验)
7483
{
7584
provide: APP_PIPE,

src/interceptors/api.interceptor.ts

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import {
2+
CallHandler,
3+
ExecutionContext,
4+
HttpException,
5+
HttpStatus,
6+
Injectable,
7+
NestInterceptor,
8+
} from '@nestjs/common';
9+
import { LoginTokenDataVo } from '@src/api/login/vo/login.vo';
10+
import { AccountTypeEnum } from '@src/enums/account.type.enum';
11+
import { Observable } from 'rxjs';
12+
13+
@Injectable()
14+
export class ApiInterceptor implements NestInterceptor {
15+
// 可以直接访问的
16+
private readonly whiteUrlList: string[] = ['/menus/btnList', '/menus'];
17+
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
18+
const request = context.switchToHttp().getRequest();
19+
/**当前请求方式 */
20+
const method = request.method;
21+
/**当前请求路径 */
22+
const url = request.url;
23+
const user = request.user as LoginTokenDataVo;
24+
const newUrl = url
25+
.replace('//', '/') // 去除双//
26+
.replace('/api/v1/admin', '') // 去除双//
27+
.replace(/\?.*/, '') // 去除最后一个
28+
.replace(/(\d+)$/, '*');
29+
console.log(newUrl, '-------------');
30+
if (this.whiteUrlList.includes(newUrl)) {
31+
return next.handle();
32+
}
33+
if (user) {
34+
const {
35+
userInfo: { accountType },
36+
} = user;
37+
if (accountType == AccountTypeEnum.SUPER_ACCOUNT) {
38+
return next.handle();
39+
}
40+
// 表示已经登录的
41+
const currentItem = user.authApi.find((item) => item.method == method && item.url == newUrl);
42+
console.log(currentItem, '???');
43+
if (currentItem) {
44+
return next.handle();
45+
} else {
46+
throw new HttpException(
47+
JSON.stringify({ code: 10034, message: '你没权限访问' }),
48+
HttpStatus.OK
49+
);
50+
}
51+
}
52+
return next.handle();
53+
}
54+
}

src/interceptors/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export * from './logger.interceptor';
22
export * from './redis-limit.interceptor';
33
export * from './redis-cache.interceptor';
4+
export * from './api.interceptor';

0 commit comments

Comments
 (0)