Reputation: 671
I'm trying to make the frontend secured by only letting certain Id's getting access. I want that If someone try to enter any route except for /login/:id
, he'll get page-not-found if he didn't logged already, but it's not working.
These are my routing table and guard:
EDIT: I solved the problem and update the code:
app-routing.module.ts
// Routing array - set routes to each html page
const appRoutes: Routes = [{
path: 'login/:id',
canActivate: [AuthGuard],
children: []
},
{
path: '',
canActivate: [AuthGuard],
canActivateChild: [AuthGuard],
children: [{
path: '',
redirectTo: '/courses',
pathMatch: 'full'
},
{
path: 'courses',
component: CourseListComponent,
pathMatch: 'full'
},
{
path: 'courses/:courseId',
component: CourseDetailComponent,
pathMatch: 'full'
},
{
path: 'courses/:courseId/unit/:unitId',
component: CoursePlayComponent,
children: [{
path: '',
component: CourseListComponent
},
{
path: 'lesson/:lessonId',
component: CourseLessonComponent,
data: {
type: 'lesson'
}
},
{
path: 'quiz/:quizId',
component: CourseQuizComponent,
data: {
type: 'quiz'
}
}
]
}
]
},
{
path: '**',
component: PageNotFoundComponent,
pathMatch: 'full'
}
];
auth.guard.ts
canActivate(route: ActivatedRouteSnapshot, state:
RouterStateSnapshot): boolean |
Observable<boolean> | Promise<boolean> {
// save the id from route snapshot
const id = +route.params.id;
// if you try to logging with id
if (id) {
this.authUserService.login(id);
// if there was error - return false
if (this.authUserService.errorMessage) {
this.router.navigate(["/page_not_found"]);
return false;
}
// there wasn't any errors - redirectTo courses and
// continue
else {
this.router.navigate(["courses"]);
return true;
}
}
// if you already logged and just navigate between pages
else if (this.authUserService.isLoggedIn())
return true;
else {
this.router.navigate(["/page_not_found"]);
return false;
}
}
canActivateChild(route: ActivatedRouteSnapshot, state:
RouterStateSnapshot): boolean |
Observable<boolean> | Promise<boolean> {
return this.canActivate(route, state);
}
auth-user.service.ts
export class AuthUserService implements OnDestroy {
private user: IUser;
public errorMessage: string;
isLoginSubject = new BehaviorSubject<boolean>(this.hasToken());
constructor(private userService: UserService) {}
// store the session and call http get
login(id: number) {
this.userService.getUser(id).subscribe(
user => {
this.user = user;
localStorage.setItem('user', JSON.stringify(this.user));
localStorage.setItem('token', 'JWT');
this.isLoginSubject.next(true);
},
error => this.errorMessage = <any>error
);
}
// if we have token the user is loggedIn
// @returns {boolean}
private hasToken(): boolean {
return !!localStorage.getItem('token');
}
// @returns {Observable<T>}
isLoggedIn(): Observable<boolean> {
return this.isLoginSubject.asObservable();
}
// clear sessions when closing the window
logout() {
localStorage.removeItem('user');
localStorage.removeItem('token');
this.isLoginSubject.next(false);
}
ngOnDestroy() {
this.logout();
}
Upvotes: 2
Views: 2883
Reputation: 671
So I managed to solve this problem. I added to the route of login/:id children: [] and changed the isLoggedIn to be behaviorSubject so the token won't change after refresh or moving between pages and it worked. I updated the code in the post so everyone could see the solution
Upvotes: 5
Reputation: 432
change this line:
const id = route.params.id;
to
const id = +route.params.id; // to convert from string to number (it's string from route params)
and one more thing, I'm not sure you should navigate to a page not found like you did ['**']
instead do this: ['/page_not_found']
now I know that 'page_not_found' does not exist in your route but that's the point, because of it, the user will be redirected to a page not found as you wanted
Upvotes: 2