중요: 클라이언트 가드만으로 접근 제어를 구현하지 마세요. 웹 브라우저에서 실행되는 모든 JavaScript는 브라우저 사용자가 수정할 수 있습니다. 클라이언트 가드와 별개로 서버에서도 항상 사용자 권한을 검사해야 합니다.
라우팅 규칙 가드는 사용자가 특정 라우팅 규칙으로 이동하거나 해당 라우팅 규칙을 떠날 수 있는지 제어하는 함수입니다. 사용자가 특정 라우팅 규칙에 접근할 수 있는지 관리하는 검문소와 비슷합니다. 인증과 접근 제어가 대표적인 사용 사례입니다.
라우팅 규칙 가드 생성하기
Angular CLI로 라우팅 규칙 가드를 생성할 수 있습니다.
ng generate guard CUSTOM_NAME
이 명령을 실행하면 사용할 라우팅 규칙 가드 종류를 선택하라는 안내가 표시되고, 선택에 맞는 CUSTOM_NAME-guard.ts 파일이 생성됩니다.
팁: Angular 프로젝트에 별도의 TypeScript 파일을 만들어 라우팅 규칙 가드를 직접 작성할 수도 있습니다.
다른 파일과 구분하기 위해 일반적으로 파일 이름 끝에 -guard.ts를 붙입니다.
라우팅 규칙 가드의 반환 타입
모든 라우팅 규칙 가드는 같은 반환 타입을 지원하기 때문에 내비게이션을 유연하게 제어할 수 있습니다.
| 반환 타입 | 설명 |
|---|---|
boolean |
true는 내비게이션을 허용하고, false는 차단합니다(CanMatch 라우팅 규칙 가드는 아래 참고 사항을 확인하세요). |
UrlTree 또는 RedirectCommand |
내비게이션을 차단하는 대신 다른 라우팅 규칙으로 리다이렉트합니다. |
Promise<T> 또는 Observable<T> |
라우터가 처음 방출된 값을 사용한 뒤 구독을 해제합니다. |
참고: CanMatch는 다르게 동작합니다.
false를 반환하면 Angular는 내비게이션을 완전히 차단하는 대신 매칭할 수 있는 다른 라우팅 규칙을 확인합니다.
라우팅 규칙 가드 종류
Angular는 용도에 따라 네 가지 라우팅 규칙 가드를 제공합니다.
모든 가드는 라우팅 규칙 수준에서 제공하는 서비스에 접근할 수 있으며, route 인자로 해당 라우팅 규칙의 정보에도 접근할 수 있습니다.
CanActivate
CanActivate 가드는 사용자가 라우팅 규칙에 접근할 수 있는지 결정합니다.
주로 인증과 권한 확인에 사용합니다.
다음 기본 인자를 사용할 수 있습니다.
route:ActivatedRouteSnapshot— 활성화하려는 라우팅 규칙의 정보가 있습니다.state:RouterStateSnapshot— 라우터의 현재 상태가 있습니다.
일반적인 가드 반환 타입을 반환할 수 있습니다.
export const authGuard: CanActivateFn = (
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot,
) => {
const authService = inject(AuthService);
return authService.isAuthenticated();
};
팁: 사용자를 리다이렉트해야 한다면 URLTree나 RedirectCommand를 반환하세요.
false를 반환한 다음 코드로 navigate를 실행하는 방식은 사용하지 마세요.
자세한 내용은 CanActivateFn API 문서를 참고하세요.
CanActivateChild
CanActivateChild 가드는 사용자가 특정 부모 라우팅 규칙의 자식 라우팅 규칙에 접근할 수 있는지 결정합니다.
중첩 라우팅 규칙의 전체 영역을 보호하려는 경우에 유용합니다.
즉, canActivateChild는 모든 자식에 적용됩니다.
자식 컴포넌트 아래에 또 다른 자식 컴포넌트가 있으면 canActivateChild는 각 컴포넌트에 대해 한 번씩 실행됩니다.
다음 기본 인자를 사용할 수 있습니다.
childRoute:ActivatedRouteSnapshot— 활성화하려는 자식 라우팅 규칙의 "미래" 스냅샷(라우터가 이동하려는 상태) 정보가 있습니다.state:RouterStateSnapshot— 라우터의 현재 상태가 있습니다.
일반적인 가드 반환 타입을 반환할 수 있습니다.
export const adminChildGuard: CanActivateChildFn = (
childRoute: ActivatedRouteSnapshot,
state: RouterStateSnapshot,
) => {
const authService = inject(AuthService);
return authService.hasRole('admin');
};
자세한 내용은 CanActivateChildFn API 문서를 참고하세요.
CanDeactivate
CanDeactivate 가드는 사용자가 라우팅 규칙을 떠날 수 있는지 결정합니다.
저장하지 않은 폼을 남겨두고 다른 곳으로 이동하지 못하게 하는 경우에 자주 사용합니다.
다음 기본 인자를 사용할 수 있습니다.
component:T— 비활성화하려는 컴포넌트 인스턴스입니다.currentRoute:ActivatedRouteSnapshot— 현재 라우팅 규칙 정보가 있습니다.currentState:RouterStateSnapshot— 현재 라우터 상태가 있습니다.nextState:RouterStateSnapshot— 이동하려는 다음 라우터 상태가 있습니다.
일반적인 가드 반환 타입을 반환할 수 있습니다.
export const unsavedChangesGuard: CanDeactivateFn<Form> = (
component: Form,
currentRoute: ActivatedRouteSnapshot,
currentState: RouterStateSnapshot,
nextState: RouterStateSnapshot,
) => {
return component.hasUnsavedChanges()
? confirm('You have unsaved changes. Are you sure you want to leave?')
: true;
};
자세한 내용은 CanDeactivateFn API 문서를 참고하세요.
CanMatch
CanMatch 가드는 경로 매칭 과정에서 라우팅 규칙을 매칭할 수 있는지 결정합니다.
다른 가드와 달리 거부하더라도 내비게이션을 완전히 차단하지 않고 다음 라우팅 규칙의 매칭을 시도합니다.
기능 플래그, A/B 테스트, 조건부 라우팅 규칙 로딩에 유용합니다.
다음 기본 인자를 사용할 수 있습니다.
route:Route— 평가 중인 라우팅 규칙 설정입니다.segments:UrlSegment[]— 앞서 부모 라우팅 규칙을 평가하면서 아직 처리하지 않은 URL 세그먼트입니다.currentSnapshot: PartialMatchRouteSnapshot— 매칭 과정에서 현재 지점까지의 라우팅 규칙 스냅샷입니다.
일반적인 가드 반환 타입을 반환할 수 있습니다.
다만 false를 반환하면 Angular는 내비게이션을 완전히 차단하는 대신 매칭할 수 있는 다른 라우팅 규칙을 확인합니다.
export const featureToggleGuard: CanMatchFn = (
route: Route,
segments: UrlSegment[],
currentSnapshot: PartialMatchRouteSnapshot,
) => {
const featureService = inject(FeatureService);
return featureService.isFeatureEnabled('newDashboard');
};
같은 경로에서 서로 다른 컴포넌트를 사용할 수도 있습니다.
routes.ts
const routes: Routes = [
{
path: 'dashboard',
component: AdminDashboard,
canMatch: [adminGuard],
},
{
path: 'dashboard',
component: UserDashboard,
canMatch: [userGuard],
},
];
이 예제에서 사용자가 /dashboard에 방문하면 가드 조건을 충족하는 첫 번째 라우팅 규칙을 사용합니다.
자세한 내용은 CanMatchFn API 문서를 참고하세요.
라우팅 규칙에 가드 적용하기
라우팅 규칙 가드를 생성했으면 라우팅 규칙 정의에 설정해야 합니다.
하나의 라우팅 규칙에 여러 가드를 적용할 수 있도록 라우팅 규칙 설정에서는 가드를 배열로 지정합니다.
라우터는 배열에 나열된 순서대로 가드를 시작하지만, 앞의 가드가 끝날 때까지 기다렸다가 다음 가드를 시작하지는 않습니다. 따라서 Promise나 Observable을 반환하는 가드는 동시에 실행됩니다.
배열 순서는 어떤 결과를 우선할지 결정합니다. 모든 가드가 true를 반환해야 내비게이션이 계속됩니다. 그렇지 않으면 뒤의 가드가 먼저 끝났더라도 배열에서 true를 반환하지 않은 첫 번째 가드의 결과를 사용합니다.
NOTE: 비동기 가드는 동시에 실행되므로 현재 사용자 정보를 불러오는 작업처럼 같은 배열의 앞선 가드가 수행하는 작업에 의존하면 안 됩니다. 두 가드가 함께 사용하는 서비스에서 해당 작업을 수행하거나, 검사들을 하나의 가드로 합치세요.
import {Routes} from '@angular/router';
import {authGuard} from './guards/auth.guard';
import {adminGuard} from './guards/admin.guard';
import {canDeactivateGuard} from './guards/can-deactivate.guard';
import {featureToggleGuard} from './guards/feature-toggle.guard';
const routes: Routes = [
// 기본 CanActivate: 인증이 필요합니다.
{
path: 'dashboard',
component: Dashboard,
canActivate: [authGuard],
},
// 여러 CanActivate 가드: 인증과 관리자 역할이 모두 필요합니다.
{
path: 'admin',
component: Admin,
canActivate: [authGuard, adminGuard],
},
// CanActivate + CanDeactivate: 저장하지 않은 변경사항을 확인하는 보호 라우팅 규칙입니다.
{
path: 'profile',
component: Profile,
canActivate: [authGuard],
canDeactivate: [canDeactivateGuard],
},
// CanActivateChild: 모든 자식 라우팅 규칙을 보호합니다.
{
path: 'users', // /user: 보호되지 않습니다.
canActivateChild: [authGuard],
children: [
// /users/list: 보호됩니다.
{path: 'list', component: UserList},
// /users/detail/:id: 보호됩니다.
{path: 'detail/:id', component: UserDetail},
],
},
// CanMatch: 기능 플래그에 따라 조건부로 라우팅 규칙을 매칭합니다.
{
path: 'beta-feature',
component: BetaFeature,
canMatch: [featureToggleGuard],
},
// 베타 기능이 비활성화되었을 때 사용할 대체 라우팅 규칙
{
path: 'beta-feature',
component: ComingSoon,
},
];