Правильно. Не работает. Поэтому есть 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, время: 10:42. |