Ответ 1
Вот 3 способа сделать то, что вы просили, от наименее предпочтительного до любимого:
Вариант 1. AppComponent
перенаправить пользователя в AppComponent
@Component({
selector: 'app-root',
template: '...'
})
export class AppComponent {
constructor(authService: AuthService, router: Router) {
if (authService.isLoggedIn()) {
router.navigate(['dashboard']);
}
}
}
Не очень хорошо. Лучше сохранить информацию "требуется вход в систему" в объявлении маршрута, к которому она относится.
Вариант 2. Использование CanActivate
guard
Добавьте CanActivate
guard ко всем маршрутам, которые требуют входа пользователя:
const APPROUTES: Routes = [
{path: 'home', component: AppComponent, canActivate:[LoginActivate]},
{path: 'dashboard', component: DashBoardComponent, canActivate:[LoginActivate]},
{path: 'login', component: LoginComponent},
{path: '**', component: NotFoundComponent}
];
Моя охрана называется LoginActivate
.
Чтобы это работало, я должен добавить охрану к своим providers
модулей.
И тогда мне нужно это реализовать. В этом примере я буду использовать Guard для перенаправления пользователей, если они не вошли в систему:
@Injectable()
export class LoginActivate implements CanActivate {
constructor(private authService: AuthService, private router: Router) {}
canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<boolean>|Promise<boolean>|boolean {
if (!this.authService.isLoggedIn()) {
this.router.navigate(['login']);
}
return true;
}
}
Посмотрите документ об охране маршрута, если это не имеет смысла: https://angular.io/docs/ts/latest/guide/router.html#guards
Этот вариант лучше, но не супер гибкий. Что, если нам нужно проверить другие условия, кроме "авторизованных", таких как права пользователя? Что если нам нужно передать какой-то параметр охраннику, например, имя роли "admin", "editor"...?
Вариант 3. Использование свойства data
маршрута
Наилучшее решение IMHO - добавить некоторые метаданные в объявление маршрутов, чтобы указать "этот маршрут требует входа пользователя".
Для этого мы можем использовать свойство data
маршрута. Он может содержать произвольные данные, и в этом случае я выбрал включить requiresLogin
флаг, либо true
или false
(false
будет по умолчанию, если флаг не определен):
const APPROUTES: Routes = [
{path: 'home', component: AppComponent, data:{requiresLogin: true}},
{path: 'dashboard', component: DashBoardComponent, data:{requiresLogin: true}}
];
Теперь свойство data
само по себе ничего не делает. Но я могу использовать его для усиления логики "требуется логин". Для этого мне снова CanActivate
охранник CanActivate
.
Слишком плохо, говорите вы. Теперь мне нужно добавить 2 вещи для каждого защищенного маршрута: метаданные И охранник...
НО:
- Вы можете прикрепить
CanActivate
guard к маршруту верхнего уровня, и он будет выполнен для всех его дочерних маршрутов [ПОДТВЕРЖДЕНО]. Таким образом, вам нужно использовать охранник только один раз. Конечно, это работает только в том случае, если все защищаемые маршруты являются дочерними по отношению к родительскому маршруту (что не имеет место в примере с Рафаэлем Моурой). - Свойство
data
позволяет нам передавать охранникам все виды параметров, например, имя конкретной роли или разрешение на проверку, количество баллов или кредитов, которые пользователь должен иметь для доступа к странице и т.д.
Принимая во внимание эти замечания, лучше всего переименовать охрану во что-то более общее, например AccessGuard
.
Я покажу только фрагмент кода, в котором охранник получает data
прикрепленные к маршруту, поскольку то, что вы делаете внутри охранника, действительно зависит от вашей ситуации:
@Injectable()
export class AccessGuard implements CanActivate {
canActivate(route: ActivatedRouteSnapshot): Observable<boolean>|Promise<boolean>|boolean {
const requiresLogin = route.data.requiresLogin || false;
if (requiresLogin) {
// Check that the user is logged in...
}
}
}
Для выполнения вышеуказанного кода вам необходим маршрут, подобный следующему:
{
path: 'home',
component: AppComponent,
data: { requiresLogin: true },
canActivate: [ AccessGuard ]
}
NB. Не забудьте добавить AccessGuard
своим providers
модулей.