Pochodzę ze świata Asp.Net MVC, w którym użytkownicy próbujący uzyskać dostęp do nieautoryzowanej strony są automatycznie przekierowywani na stronę logowania.
Próbuję odtworzyć to zachowanie w Angular. Natknąłem się na dekorator @CanActivate, ale powoduje to, że komponent w ogóle nie renderuje się, nie ma przekierowania.
Moje pytanie jest następujące:
- Czy Angular zapewnia sposób na osiągnięcie takiego zachowania?
- Jeśli tak to jak? Czy to dobra praktyka?
- Jeśli nie, jaka byłaby najlepsza praktyka w zakresie obsługi autoryzacji użytkowników w Angular?
login
typescript
angular
angular2-routing
Amaury
źródło
źródło
Odpowiedzi:
Aktualizacja: Opublikowałem pełny projekt szkieletu Angular 2 z integracją OAuth2 na Github, który pokazuje w akcji wspomnianą poniżej dyrektywę.
Jednym ze sposobów byłoby użycie pliku
directive
. W przeciwieństwie do Angular 2components
, które są w zasadzie nowymi tagami HTML (z powiązanym kodem), które wstawiasz do swojej strony, dyrektywa atrybucyjna to atrybut, który umieszczasz w tagu, który powoduje pewne zachowanie. Dokumenty tutaj .Obecność atrybutu niestandardowego powoduje, że coś dzieje się z komponentem (lub elementem HTML), w którym umieściłeś dyrektywę. Rozważ tę dyrektywę, której używam dla mojej obecnej aplikacji Angular2 / OAuth2:
Wykorzystuje to usługę uwierzytelniania, o której pisałem, w celu ustalenia, czy użytkownik jest już zalogowany, czy też nie, a także subskrybuje zdarzenie uwierzytelniania, dzięki czemu może wyrzucić użytkownika, jeśli wyloguje się lub wyloguje.
Możesz zrobić to samo. Utworzyłbyś dyrektywę taką jak moja, która sprawdza obecność niezbędnego pliku cookie lub innych informacji o stanie, które wskazują, że użytkownik jest uwierzytelniony. Jeśli nie mają tych flag, których szukasz, przekieruj użytkownika na swoją główną stronę publiczną (tak jak ja) lub na serwer OAuth2 (lub cokolwiek). Możesz umieścić ten atrybut dyrektywy na dowolnym komponencie, który musi być chroniony. W tym przypadku można by to nazwać
protected
jak w dyrektywie, którą wkleiłem powyżej.Następnie chciałbyś nawigować / przekierowywać użytkownika do widoku logowania w swojej aplikacji i tam obsługiwać uwierzytelnianie. Musiałbyś zmienić obecną trasę na tę, którą chcesz to zrobić. Więc w takim przypadku użyłbyś iniekcji zależności, aby pobrać obiekt Routera w funkcji twojej dyrektywy,
constructor()
a następnie użyjnavigate()
metody, aby wysłać użytkownika na twoją stronę logowania (jak w moim przykładzie powyżej).Zakłada się, że masz gdzieś serię tras kontrolujących
<router-outlet>
tag, który wygląda mniej więcej tak:Jeśli zamiast tego musisz przekierować użytkownika do zewnętrznego adresu URL, takiego jak serwer OAuth2, to Twoja dyrektywa powinna wykonać coś takiego:
źródło
Oto zaktualizowany przykład przy użyciu Angular 4 (również kompatybilny z Angular 5-8)
Trasy z trasą do domu chronioną przez AuthGuard
AuthGuard przekierowuje do strony logowania, jeśli użytkownik nie jest zalogowany
Zaktualizowano w celu przekazania oryginalnego adresu URL w parametrach zapytania do strony logowania
Pełny przykład i działające demo można znaleźć w tym poście
źródło
currentUser
wlocalStorage
nadal byłoby w stanie uzyskać dostęp do chronionej trasy? na przykład.localStorage.setItem('currentUser', 'dddddd')
?Użycie z końcowym routerem
Wraz z wprowadzeniem nowego routera ochrona tras stała się łatwiejsza. Musisz zdefiniować strażnika, który działa jako usługa, i dodać go do trasy.
Teraz przekaż
LoggedInGuard
trasę do trasy, a także dodaj ją doproviders
tablicy modułu.Deklaracja modułu:
Szczegółowy post na blogu o tym, jak to działa z ostateczną wersją: https://medium.com/@blacksonic86/angular-2-authentication-revisited-611bf7373bf9
Użycie z przestarzałym routerem
Bardziej niezawodnym rozwiązaniem jest rozszerzenie
RouterOutlet
i podczas aktywacji sprawdzania trasy, czy użytkownik jest zalogowany. W ten sposób nie musisz kopiować i wklejać dyrektywy do każdego komponentu. Ponadto przekierowania oparte na składniku podrzędnym mogą wprowadzać w błąd.Plik
UserService
Stoi w miejscu, gdzie mieszka twoja logika biznesowa, czy użytkownik jest zalogowany czy nie. Możesz go łatwo dodać za pomocą DI w konstruktorze.Gdy użytkownik przejdzie do nowego adresu URL w Twojej witrynie, metoda aktywacji jest wywoływana z aktualną instrukcją. Z niego możesz pobrać adres URL i zdecydować, czy jest to dozwolone, czy nie. Jeśli nie, po prostu przekieruj do strony logowania.
Ostatnią rzeczą, która pozostała, aby to zadziałało, jest przekazanie go do naszego głównego komponentu zamiast do wbudowanego.
Tego rozwiązania nie można używać z
@CanActive
dekoratorem cyklu życia, ponieważ jeśli przekazana do niego funkcja rozwiąże wartość false, metoda aktywacji elementuRouterOutlet
nie zostanie wywołana.Napisałem również na ten temat szczegółowy post na blogu: https://medium.com/@blacksonic86/authentication-in-angular-2-958052c64492
źródło
Failed to lint <classname>.router-outlet.ts[15,28]. In the constructor of class "LoggedInRouterOutlet", the parameter "nameAttr" uses the @Attribute decorator, which is considered as a bad practice. Please, consider construction of type "@Input() nameAttr: string".
Nie mogłem określić, co należy zmienić w konstruktorze („_parentRounter”), aby pozbyć się tego komunikatu. jakieś pomysły?_parentRouter: Router, @Input() nameAttr: string,
a tslint nie powoduje już błędu. Zastąpiono także import „Atrybutów” na „Dane wejściowe” z kątowego rdzenia. Mam nadzieję że to pomoże.Proszę, nie zastępuj Router Outlet! To koszmar z najnowszą wersją routera (3.0 beta).
Zamiast tego użyj interfejsów CanActivate i CanDeactivate i ustaw klasę jako canActivate / canDeactivate w definicji trasy.
Tak:
Klasa:
Zobacz też: https://angular.io/docs/ts/latest/guide/router.html#!#can-activate-guard
źródło
Idąc za wspaniałymi odpowiedziami powyżej, chciałbym również
CanActivateChild
: pilnować dziecięcych tras. Można go użyć do dodaniaguard
do podrzędnych tras pomocnych w przypadkach takich jak listy ACLTak to wygląda
To pochodzi z https://angular.io/docs/ts/latest/guide/router.html#!#can-activate-guard
źródło
Zobacz ten kod, plik auth.ts
źródło
1. Create a guard as seen below. 2. Install ngx-cookie-service to get cookies returned by external SSO. 3. Create ssoPath in environment.ts (SSO Login redirection). 4. Get the state.url and use encodeURIComponent.
źródło