NestJS로 승인 준비 관리자 패널을 만드는 방법은 무엇입니까?

설명된 모든 단계는 이 문서repo에 있습니다.

소개



에서는 API와 함께 nestjs을, 관리자 패널에서는 refine을 사용했습니다. 이 블로그에서는 api와 관리자 패널 모두에 권한을 추가해 보겠습니다.

대본



이 시스템에서 두 가지 역할, 즉 admineditor를 가집니다. 우리가 준비한 API에는 companiesjobs 로 분류한 두 가지 조악한 프로세스가 있습니다.

이 시나리오에서; editor는 회사만 나열할 수 있으며 삭제나 추가는 불가능합니다. 채용 공고를 나열하고 작성할 수 있는 권한이 있습니다. admin가 모든 트랜잭션에 대한 권한을 갖도록 합니다.

권한 부여



준비한 api에서 nestjsx-crud을 사용했습니다. 이 라이브러리는 CRUD 작업을 매우 쉽게 만듭니다. 그러나 인증 측에서는 지원되지 않습니다. 그래서 nestjsrefine 모두와 쉽게 통합할 수 있는 accesscontrol 라이브러리를 사용했습니다.

API에서 AccessControl 사용



첫 번째 단계에서는 API에 대한 accesscontrol 통합을 위해 프로젝트에 nestjs-access-control을 설치해 보겠습니다.

npm install nest-access-control

AccessControl에서 지원하는 역할을 지정하고 있습니다. 시나리오에 따르면 다음과 같아야 합니다.

// app.roles.ts

import { RolesBuilder } from 'nest-access-control';

export enum AppRoles {
  ADMIN = 'ADMIN',
  EDITOR = 'EDITOR',
}

export const roles: RolesBuilder = new RolesBuilder();

roles
  // editor
  .grant(AppRoles.EDITOR)
  .create('jobs')
  .update('jobs')
  // admin
  .grant(AppRoles.ADMIN)
  .extend(AppRoles.EDITOR)
  .create(['companies'])
  .update(['companies'])
  .delete(['companies', 'jobs']);


이제 AccessControlModule를 가져옵니다.

  // app.module.ts

  import { roles } from './app.roles';

    @Module({
      imports: [
        ...
        AccessControlModule.forRoles(roles)
      ],
      controllers: [...],
      providers: [...],
    })
    export class AppModule {}


역할과 권한을 결정한 후 ACGuard 클래스를 컨트롤러UseGuards에 추가합니다.

import { ACGuard } from 'nest-access-control';

...
@UseGuards(JwtAuthGuard, ACGuard)
@Controller('companies')
export class CompanyController implements CrudController<CompanyEntity> {}
...


이제 UseRoles 데코레이터를 사용하여 메서드에 대한 리소스 및 작업을 정의합니다. 예를 들어 다음과 같이 companies 리소스와 create 작업을 재정의합니다.

import { ACGuard, UseRoles } from 'nest-access-control';

...
@UseGuards(JwtAuthGuard, ACGuard)
@Controller('companies')
export class CompanyController implements CrudController<CompanyEntity> {
  constructor(public service: CompanyService) {}

  get base(): CrudController<CompanyEntity> {
    return this;
  }

  @Override()
  @UseRoles({
    resource: 'companies',
    action: 'create',
  })
  createOne(
    @ParsedRequest() req: CrudRequest,
    @ParsedBody() dto: CompanyCreateDto,
  ) {
    return this.base.createOneBase(req, <CompanyEntity>dto);
  }
...


마찬가지로 다른 메서드에 이 데코레이터를 추가합니다.

이러한 작업 후에 API 측에서 인증 프로세스를 완료합니다. 이제 refine로 생성한 관리자 패널에 대한 인증을 수행합니다.

구체화에서 AccessControl 사용(대시보드)



정제하다; 그것은 매우 유연한 많은 인증 도구를 지원합니다. 우리가 해야 할 일; accessControlProvider 구성 요소 내부에 <Refine />를 정의합니다.
accessControlProvider 요청된 액세스 권한 부여 여부를 제어하는 ​​데 사용할 수 있는 "can"이라는 비동기 메서드 하나만 구현됩니다. 이 메서드는 resourceaction를 매개 변수와 함께 사용합니다.

// App.tsx

<Refine
  ...
  accessControlProvider={{
    can: async ({ resource, action }) => {
      let can: boolean = false;
      const stringifyUser = localStorage.getItem('refine-user');
      if (stringifyUser) {
        const { roles } = JSON.parse(stringifyUser);

        roles.forEach((role: string) => {
          switch (action) {
            case 'list':
            case 'show':
              can = ac.can(role).read(resource).granted;
              break;
            case 'create':
              can = ac.can(role).create(resource).granted;
              break;
            case 'edit':
              can = ac.can(role).update(resource).granted;
              break;
            case 'delete':
              can = ac.can(role).delete(resource).granted;
              break;
          }
        });
      }
      return Promise.resolve({ can });
    },
  }}
/>****


이제 제가 작성한 이 코드에 대해 조금 설명하겠습니다. 먼저 로그인한 사용자의 역할이 필요합니다. 로그인하는 동안 로컬 저장소에 저장했습니다.
그런 다음 세분화actions를 accessControl의 작업과 일치시키고 granted 메서드로 승인을 확인합니다. 반환된 결과도 해결합니다.

결론



그 결과 ui(대시보드) 측과 api 측 모두에서 권한 부여를 완료했습니다.

좋은 웹페이지 즐겨찾기