Правильно. Не работает. Поэтому есть 2 совета:
1. Вынести функцию isAuthenticated из гуарда в сервис юзеров. Это, так сказать, разделение ответственносте. Гуарды гуардят, а юзерсервисы юзерсервисят. 2. Проставление типов any облегчает жизнь нерадивому разрабу, но следующего по пути дзена просветляют и научает. Ибо, если бы у вас стоял не any, а Observable<User>, то вы бы поняли, что совать его в условный оператор бессмысленно. Функция асинхронная. Тут конечно вопрос: у вас пользователь, которого вы сравниваете в 17 строке где-то хранится локально? Если да, то и асинхрон не нужен. Если вы его читаете с сервера, то нужен. Но тут такая ситуация, ежли вы по каждому перемещению по роутам будете сервер дергать, то это очень не хорошо. Итог: 1. isAuthenticated -- несем в изер сервис 2. Юзера читаем при инициализации и храним в том же юзер сервисе, либо создаем authService. 3. При перемещении по роуту избавляемся от асинхрона и выполняем обычные синхронные функции. 4. Если асинхронный подход нужен, то функцию isAuthenticated надо переписать под Observable. 5. Типизируем! Ангуляр довольно сложен, а типы помогут вам определиться с тем, что вы ожидаете получить. Если вас разочаровывают ошибки в процессе написания это говорит, что вы что-то не поняли и надо копать в этом направлении. |
Для меня это пока темный лес. Сохранил на потом, а пока хоть как-то сделать, но чтобы заработало.
Уже вторые сутки методом тыка пытаюсь вернуть логин из функции. public isAuthenticated(): any { this.userService.getUser().subscribe(data => (this.user = data)); // Здесь как то надо увидеть this.user.login } |
Цитата:
Для Юзер сервиса дописываем функцию:
export class UserService{
isAutentificated: boolean = false;
userInfo: UserInfo
constructor(
http: HttpService
){}
// Синхронная!
isAuthenticated(): boolean {
return this.isAutentificated;
}
// Асинхронная
authUser(data: {login: string, password}){
this.gttp.post('api/url').subscribe(
(data: UserInfo) => {
if(data){
this.userInfo = data;
this.isAutentificated = true;
}
}
);
}
}
authUser вызываем после того, как в форме логина вводим логин и пароль. Из компонента логина. А теперь ваш код в гуарде:
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) : Observable<boolean> | boolean{
if(this.userService.isAuthenticated()) { // Сейчас придет. Функция синхронная.
return true;
} else {
this.router.navigate(['/login']);
}
}
Если isAuthenticated все-же должен быть асинхронным, то подход другой. Что-то типа такого (вы же понимаете, что и код функции isAuthenticated будет через обсерверы и не такой как в примере выше):
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) : Observable<boolean> | boolean{
return this.userService.isAuthenticated()
.subscribe( (data: boolean) => {
return data;
});
}
Что-то типа так. Пусть меня поправят более опытные товарищи. Пишу навскидку. Но смысл таков: если функция асинхронная, подписываемся на нее и полученный в подписке рузультат возвращаем. Когды вы выставите тыпы в вашем коде среда разработки подскажет вам какие функции можно вписать. |
Это в userService
public isAuthenticated(): Observable<boolean> {
return this.getUser().pipe(
map(data => !!data['login'])
);
}
это в authGuard
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) : Observable<boolean>{
return this.userService.isAuthenticated().pipe(
tap((isAuthenticated: boolean) => {
if (!isAuthenticated) {
this.router.navigate(['/login'])
}
})
);
}
|
sniffysko, destus, огромное спасибо за примеры. Буду вникать поглубже, но теперь уже только после нг.
Если честно, то я даже не понимаю пока как оформлять функцию синхронной или наоборот. Жс у меня со скрипом всегда шел и понять его никак не могу. Вообще я делаю простую админку, не для массового использования, с целью познакомится с ангуляром. Это последнее из того что осталось сделать, чтобы был каркас, дальше уже думаю справлюсь самостоятельно. Я так вижу: мне нужена синхронная функция, так как проверка авторизации нужна только при переходе между страницами и при совершении каких-либо действий на сервере. Зачем асинхронная в данном случае не понимаю, но было бы интересно. Всех фронтовиков с наступающим! И до новых встреч ) |
Не актуально
А можете объяснить (неудобно наглеть, но желательно с примером), почему в этой конструкции не работает this.router.navigate(['/login']); Там конечно легко накостылировать на ЖС, но хочется правильно все сделать
// this.router.navigate(['/login']); // Тут работает
return this.userService.isAuthenticated().pipe(
tap((isAuthenticated: boolean) => {
if (!isAuthenticated) {
this.router.navigate(['/login']); // А тут нет
} else {
return true;
}
})
);
В общем, как часто бывает, немного затупил - зацикливалось Хотел сделать так: { path: 'login', component: LoginComponent, canActivate: [AuthGuard] } Чтобы страницу логина было видно в canActivate и если авторизация есть, то переадресация на главную
return this.userService.isAuthenticated().pipe(
tap((isAuthenticated: boolean) => {
if (!isAuthenticated && route.url.join() != 'login') { // но почему-то это условие не срабатывает (&& route.url.join() != 'login'). Если нет авторизации бросает на страницу логина, а потом с нее же на нее. Это я так понимаю, а вообще в корень отправляет. Без ошибок в консоли
this.router.navigate(['/login']);
} else {
return true;
}
|
| Часовой пояс GMT +3, время: 06:28. |