In my application, the user logs in and receives a JWT, which is stored in local storage. After the user is authenticated, there's a following call to the server to determine the user's roles and functions (what pages they can visit).
My problem is that when a user wants to open a page (resuming old session, duplicating tab, passing URL to someone else, etc.), the app doesn't have authorization details and must first request them, the role guard kicks in. This results in the user being redirected to the login page.
@Injectable({
providedIn: 'root'
})
export class RoleGuardService implements CanActivate {
constructor(public auth: AuthService, public router: Router, public globalConfig: GlobalConfigService) { }
canActivate(route: ActivatedRouteSnapshot): boolean {
if (!this.auth.isAuthenticated()) {
this.router.navigate(['login']);
return false;
}
const expectedFunction = route.data.expectedFunction;
if (!this.globalConfig.hasFunction(expectedFunction)) {
this.router.navigate(['login']);
return false;
}
return true;
}
}
The expected function is defined in routes, example:
{
path: 'system-admin', loadChildren: () => SystemAdminModule,
data: { breadcrumb: 'System Admin', expectedFunction: FunctionType.SystemAdministration }, canActivate: [RoleGuard]
},
The hasFunction
body in the GlobalConfigService
looks like this:
private authorizedUser: AuthorizedUser = new AuthorizedUser();
public hasFunction(expectedFunction: FunctionType): boolean {
return !!this.authorizedUser.functions
&& this.authorizedUser.functions.find(f => f === expectedFunction) !== undefined;
}
Authorization done in the AuthService
is done as follows:
public onAuthorized = new Subject<AuthorizedUser>();
authorize() {
const url = environment.APIURL + 'auth/currentuser';
return this.http.get(url).subscribe(
resp => {
this.globalConfig.AuthorizedUser = resp;
this.onAuthorized.next(resp as AuthorizedUser);
}
);
}
And authorize()
is called from the ngOnInit()
in the AppComponent
ngOnInit(): void {
if (this.auth.isAuthenticated()) {
this.auth.authorize();
} else {
this.router.navigate(['login']);
}
}
I believe the solution would be to put in some wait condition if the user is authenticated, then authorization should be allowed to complete before anything else is being evaluated. Would this need to happen in RoleGuard
only, or would it span throughout the whole authentication/authorization process?