[angular] 경로 가드에 매개 변수 전달
저는 이러한 역할을 기반으로 앱의 일부에 대한 탐색을 차단하기 위해 가드를 사용해야하는 많은 역할이있는 앱을 작업하고 있습니다. 각 역할에 대해 개별 가드 클래스를 만들 수 있지만 어떻게 든 매개 변수를 전달할 수있는 하나의 클래스를 갖고 싶습니다. 즉, 다음과 유사한 작업을 수행하고 싶습니다.
{
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;
}
이를 통해 라우팅 모듈의 권한 매개 변수를 기반으로 일부 사용자 지정 가드를 등록하는 메서드를 사용할 수 있습니다.
....
{ path: 'something',
component: SomeComponent,
canActivate: [ AuthGuardService.forPermissions('permission1', 'permission2') ] },
의 흥미로운 부분 forPermission
입니다 AuthGuardService.guards.push
– 이것은 기본적으로 어떤 시간이 있는지 확인한다 forPermissions
그것은 또한이 배열에 저장하는 사용자 정의 가드 클래스를 얻기 위해 호출된다. 이것은 메인 클래스에서도 정적입니다.
public static guards = [ ];
그런 다음이 배열을 사용하여 모든 가드를 등록 할 수 있습니다. 앱 모듈이 이러한 공급자를 등록 할 때 경로가 정의되었고 모든 가드 클래스가 생성되었는지 확인하는 한 괜찮습니다 (예 : 가져 오기 순서 확인 및 이러한 공급자를 목록에서 가능한 한 낮게 유지하십시오. 라우팅 모듈이 도움이됩니다.
providers: [
// ...
AuthGuardService,
...AuthGuardService.guards,
]
도움이 되었기를 바랍니다.
답변
@AluanHaddad의 솔루션은 “제공자 없음”오류를 제공합니다. 여기에 대한 해결책이 있습니다 (더러워진 것 같지만 더 나은 것을 만드는 기술이 부족합니다).
개념적으로는 .NET에서 생성 된 동적으로 생성 된 각 클래스를 공급자로 등록합니다 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')]
더 나은 솔루션은 내부의 글로벌 공급자 컬렉션에 공급자를 자동으로 등록하는 roleGuard
것이지만 제가 말했듯이이를 구현할 기술이 부족합니다.