I'm working on a small personal app. I'll explain what I did until now and in the end my problem and my question. I have created a Node server and an Angular app. When the Angular app is booting I'm checking if the user is logged in (via http get request to the server, the request is made in app.component.ts)
ngOnInit(): void {
this.authService.checkIfUserSignedIn();
}
Inside the checkIfUserSignedIn method after that I'm getting the relevant authentication information I notify to the interested components with the auth state.
this.userAuthDetailsSubject.next(this.userAuthDetails);
Additionally, I'm having an AuthGuard that restrict the entry to the "create-list" component only to authenticated users. In the AuthGurad I'm checking the auth state:
const authStatus = this.authService.isAuth();
return authStatus;
In the menu html component I have the following code:
<span routerLink="create-list" *ngIf="userIsAuthenticated"> New List</span>
Which works fine. My problem is when i'm visiting manually localhost:4200/create-list
The AuthGuard is probably loaded before auth state is updated and therefore the user has no access to the "create-list" component, although he is signed in eventually.
I thought about two solutions but I'm not sure if they are good and how to implement them, and would like to hear your opinion.
Any ideas/solutions?
canActivate (AuthGuard):
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean | import("@angular/router").UrlTree | import("rxjs").Observable<boolean | import("@angular/router").UrlTree> | Promise<boolean | import("@angular/router").UrlTree> {
const authStatus = this.authService.isAuth();
if (authStatus) {
return true;
} else {
this.router.navigate(['/login']);
}
}
auth.service.ts
@Injectable()
export class AuthService {
userAuthDetailsSubject = new Subject<UserAuthDetails>();
userAuthDetails: UserAuthDetails = null;
private isAuthenticated = false;
constructor(@Inject(DOCUMENT) private document: Document, private http: HttpClient) {
};
public isAuth(): boolean {
console.log({
isAuth: this.isAuthenticated
})
return this.isAuthenticated;
}
signIn() {
// redirect to signin..
this.document.location.href = '/auth/google';
}
signOut() {
this.document.location.href = '/auth/logout';
}
checkIfUserSignedIn() {
this.http.get<any>('/auth/current_user').subscribe(res => {
if (res) {
this.isAuthenticated = true;
console.log('assigning true to isAuth')
this.userAuthDetails = {
displayName: res.displayName,
email: res.email,
uid: res._id
};
this.userAuthDetailsSubject.next(this.userAuthDetails);
} else {
console.log('User not authenticated')
}
})
}
}
For this particular problem you can make the 'isAuthenticated' field a subject just like 'userAuthDetailsSubject' and update its value when the server responds.
auth.service.ts
checkIfUserSignedIn() {
this.http.get<any>('/auth/current_user').subscribe(res => {
if (res) {
this.isAuthenticated.next(true); //update the value
console.log('assigning true to isAuth')
this.userAuthDetails = {
displayName: res.displayName,
email: res.email,
uid: res._id
};
this.userAuthDetailsSubject.next(this.userAuthDetails);
} else {
console.log('User not authenticated')
}
})
}
Now change your authguard so it does not return true or false synchronously.
canActivate (AuthGuard):
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot):
boolean | import("@angular/router").UrlTree |
import("rxjs").Observable<boolean | import("@angular/router").UrlTree>| Promise<boolean | import("@angular/router").UrlTree> {
return this.authService.isAuth().subscribe((logged)=>{
if (logged) {
return true;
} else {
this.router.navigate(['/login']);
return false;
}
})
}
Off topic:
import("@angular/router").UrlTree
? You can use import like import { UrlTree } from '@angular/router';
return this.router.createUrlTree(['/login']);
and not create a new async process in your canActivateOn Topic: If you call direct link, you have to resolve authentication. If you call link or F5 reload browser will lost every data from memory. If you use any token to auth it be worth saving into localStore and restore from here. Ofc, After authentication if you open new tab, this new tab will new without auth default like you used F5 on current tab. It lives a separate life for each tabs.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.