itsource

파라미터를 루트 가드에 전달합니다.

mycopycode 2023. 4. 2. 10:25
반응형

파라미터를 루트 가드에 전달합니다.

저는 많은 역할을 하는 앱을 만들고 있는데, 그 역할에 따라 앱의 일부에 대한 네비게이션을 차단하기 위해 가드를 사용해야 합니다.각 역할에 대해 개별 가드 클래스를 만들 수 있지만, 어떤 식으로든 매개 변수를 전달할 수 있는 클래스를 하나 갖고 싶습니다.즉, 다음과 같은 일을 할 수 있으면 좋겠습니다.

{ 
  path: 'super-user-stuff', 
  component: SuperUserStuffComponent,
  canActivate: [RoleGuard.forRole('superUser')]
}

하지만 통과시키는 건 가드의 유형 이름뿐이라 방법이 떠오르지 않아요.그냥 참고 역할별로 개별 가드 클래스를 쓰고, 대신 하나의 파라미터 타입을 갖는 우아함에 대한 환상을 깨야 할까요?

사용하는 대신forRole()다음과 같이 할 수 있습니다.

{ 
   path: 'super-user-stuff', 
   component: SuperUserStuffComponent,
   canActivate: [RoleGuard],
   data: {roles: ['SuperAdmin', ...]}
}

RoleGuard에서 이 기능을 사용합니다.

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot)
    : Observable<boolean> | Promise<boolean> | boolean  {

    let roles = route.data.roles as Array<string>;
    ...
}

다음은 프로바이더 누락 문제에 대한 저의 견해와 가능한 해결책입니다.

제 경우 권한 또는 권한 목록을 매개 변수로 사용하는 가드가 있지만 역할이 있는 것과 같습니다.

허가 여부에 관계없이 인증가드를 다루는 클래스가 있습니다.

@Injectable()
export class AuthGuardService implements CanActivate {

    checkUserLoggedIn() { ... }

사용자 활성 세션 확인 등에 대해 설명합니다.

또, 커스텀 허가 가드를 취득하기 위해서 사용하는 방법도 포함되어 있습니다.이것은 실제로는,AuthGuardService그 자체

static forPermissions(permissions: string | string[]) {
    @Injectable()
    class AuthGuardServiceWithPermissions {
      constructor(private authGuardService: AuthGuardService) { } // uses the parent class instance actually, but could in theory take any other deps

      canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
        // checks typical activation (auth) + custom permissions
        return this.authGuardService.canActivate(route, state) && this.checkPermissions();
      }

      checkPermissions() {
        const user = ... // get the current user
        // checks the given permissions with the current user 
        return user.hasPermissions(permissions);
      }
    }

    AuthGuardService.guards.push(AuthGuardServiceWithPermissions);
    return AuthGuardServiceWithPermissions;
  }

이를 통해 라우팅 모듈의 permission 파라미터에 따라 커스텀가드를 등록할 수 있습니다.

....
{ path: 'something', 
  component: SomeComponent, 
  canActivate: [ AuthGuardService.forPermissions('permission1', 'permission2') ] },

의 흥미로운 부분은forPermissionAuthGuardService.guards.push- 기본적으로는, 언제라도,forPermissions커스텀 가드클래스를 취득하기 위해서 호출됩니다.이 클래스도 이 배열에 저장됩니다.이것은 메인 클래스에서도 스태틱합니다.

public static guards = [ ]; 

그런 다음 이 어레이를 사용하여 모든 가드를 등록할 수 있습니다.앱 모듈이 이러한 프로바이더를 등록할 때 루트가 정의되고 모든 가드 클래스가 생성되었는지 확인하기만 하면 됩니다(예를 들어 Import 순서를 확인하고 목록에서 이러한 프로바이더를 가능한 낮게 유지하는 등 라우팅 모듈이 도움이 됩니다).

providers: [
    // ...
    AuthGuardService,
    ...AuthGuardService.guards,
]

이게 도움이 됐으면 좋겠다.

다른 옵션 조합의 접근방식은data및 공장 기능:

export function canActivateForRoles(roles: Role[]) {
  return {data: {roles}, canActivate: [RoleGuard]}
}

export class RoleGuard implements CanActivate {
  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot)
      : Observable<boolean> | Promise<boolean> | boolean  {
  
      const roles = route.data.roles as Role[];
    ...
  }
}

...

{ path: 'admin', component: AdminComponent, ...canActivateWithRoles([Role.Admin]) },

롤가드는 다음과 같이 쓸 수 있습니다.

export class RoleGuard {
  static forRoles(...roles: string[]) {

    @Injectable({
      providedIn: 'root'
    })
    class RoleCheck implements CanActivate {
      constructor(private authService: AuthService) { }
        canActivate(): Observable<boolean> | Promise<boolean> | boolean {
          const userRole = this.authService.getRole();

          return roles.includes(userRole);
        }
      }

      return RoleCheck;
    }

}

또한 다음과 같이 여러 역할과 함께 사용할 수 있습니다.

{ 
  path: 'super-user-stuff', 
  component: SuperUserStuffComponent,
  canActivate: [RoleGuard.forRoles('superUser', 'admin', 'superadmin')]
}

2022년부터는 CanActivateFn(https://angular.io/api/router/CanActivateFn)을 사용할 수 있습니다.이 함수는 CanActivateFn 인스턴스를 반환합니다.

// Returns a function which can act as a guard for a route
function requireAnyRole(...roles: Role[]): CanActivateFn {
  return (ars: ActivatedRouteSnapshot, rss: RouterStateSnapshot) => {
    // do some checks here and return true/false/observable
    // can even inject stuff with inject(ClassOrToken)
  }
}

루트를 정의할 때 사용할 수 있습니다.

{
  path: 'some/path',
  component: WhateverComponent,
  canActivate: [requireAnyRole(Role1, Role2, Role3)]
}

@AluanHaddad의 솔루션이 "공급자가 없습니다" 오류를 발생시키고 있습니다.여기 그것을 위한 해결책이 있다(더러운 느낌이 들지만, 나는 더 나은 것을 만들 기술이 부족하다).

된 각 합니다.roleGuard.

따라서 선택한 모든 역할에 대해:

canActivate: [roleGuard('foo')]

다음 조건을 충족해야 합니다.

providers: [roleGuard('foo')]

@@AluanHaddad의 됩니다.roleGuard, 「 「」의 roles파라미터가 동일합니다.「」를 사용합니다.lodash.memoize음음음같 뭇매하다

export var roleGuard = _.memoize(function forRole(...roles: string[]): Type<CanActivate> {
    return class AuthGuard implements CanActivate {
        canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot):
            Observable<boolean>
            | Promise<boolean>
            | boolean {
            console.log(`checking access for ${roles.join(', ')}.`);
            return true;
        }
    }
});

각 역할 조합은 새 클래스를 생성하므로 역할 조합마다 공급자로 등록해야 합니다.즉, 다음과 같은 경우:

canActivate: [roleGuard('foo')] ★★★★★★★★★★★★★★★★★」canActivate: [roleGuard('foo', 'bar')]다 요.providers[roleGuard('foo'), roleGuard('foo', 'bar')]

를 'Da'의 입니다.roleGuard하지만 말했듯이, 저는 그것을 구현할 기술이 부족합니다.

은 른른른 、 R 、 R 、 R 、 R 、 R 、 R 。InjectionToken을 사용법

export class AccessGuard {
  static canActivateWithRoles(roles: string[]) {
    return new InjectionToken<CanActivate>('AccessGuardWithRoles', {
      providedIn: 'root',
      factory: () => {
        const authorizationService = inject(AuthorizationService);

        return {
          canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): <boolean | UrlTree > | Promise<boolean | UrlTree> | boolean | UrlTree {
              return authorizationService.hasRole(roles);
          }
        };
      },
    });
  }
}

그리고 이렇게 사용하세요.

canActivate: [AccessGuard.canActivateWithRoles(['ADMIN'])]

해서 하는 이 있어요.useFactory ★★★★★★★★★★★★★★★★★」providers:

const routes: Routes = [
 { 
   path: 'super-user-stuff', 
   component: SuperUserStuffComponent,
   // Name can be whatever you want
   canActivate: ['CanActiveSuperUserStuffGuard']
 }
]

★★★★★★★★★★★★★★★.providers하다

@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule],
  providers: [
    {
      provide: 'CanActiveSuperUserStuffGuard',
      useFactory: () => new RoleGuard('superUser')
    }
  ]
})
export class YourRoutingModule {
}

.providedIn: 'root' 나가주세요)@Injectable()과 같이 합니다.

  constructor(@Inject('roleName') private readonly roleName: string) {
  } 

주의하세요!!!이 방법을 사용하면 모든 선언에 대해 새로운 가드인스턴스가 생성됩니다.

언급URL : https://stackoverflow.com/questions/42719445/pass-parameter-into-route-guard

반응형