Keycloak-angular: Feature: support CanLoad and CanActivateChild implementation in KeycloakAuthGuard

Created on 18 Jul 2018  路  3Comments  路  Source: mauriciovigolo/keycloak-angular

Bug Report or Feature Request (mark with an x)

- [ ] bug report -> please search for issues before submitting
- [x ] feature request

Versions.

Repro steps.

The log given by the failure.

Desired functionality.

Can we extend KeycloakAuthGuard to support CanLoad and CanActivateChild.

This will be very useful for lazy routed modules.

Most helpful comment

My current workaround/solution, for whoever needs it. @mauriciovigolo if you would like a MR, let me know.

Assuming that a route uses lazy load:

1) point to our auth guard in the respective angular route definition

       canLoad: [AuthGuard],
        loadChildren: () => import('./feature/feature.module').then(m => m.FeatureModule)

2) implement CanLoad in the AuthGuard

@Injectable()
export class AuthGuard extends KeycloakAuthGuard implements CanLoad {

    constructor(protected router: Router, protected keycloakAngular: KeycloakService) {
        super(router, keycloakAngular);
    }

    canLoad(route: Route, segments: UrlSegment[]): boolean | Observable<boolean> | Promise<boolean> {
        return new Promise(async (resolve, reject) => {
            try {
                this.authenticated = await this.keycloakAngular.isLoggedIn();
                this.roles = await this.keycloakAngular.getUserRoles(true);

                const result = await this.checkAccessAllowed(route.data);
                resolve(result);
            } catch (error) {
                reject('An error happened during access validation. Details:' + error);
            }
        });
    }

    isAccessAllowed(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean> {
        return this.checkAccessAllowed(route.data);
    }

    checkAccessAllowed(data: Data): Promise<boolean> {
        return new Promise(async (resolve, reject) => {
            if (!this.authenticated) {
                this.keycloakAngular.login().catch(e => console.error(e));
                return reject(false);
            }
            const requiredRoles = data as string[];
            if (!requiredRoles || requiredRoles.length === 0) {
                return resolve(true);
            } else {
                if (!this.roles || this.roles.length === 0) {
                    resolve(false);
                }
                let granted = false;
                for (const requiredRole of requiredRoles) {
                    if (this.roles.indexOf(requiredRole) > -1) {
                        granted = true;
                        break;
                    }
                }
                resolve(granted);
            }
        });
    }
}

All 3 comments

@NehalDamania, I will take a look at your feature request. I'm pretty busy last days, so as soon as I have some time available I will send you a feedback. Thanks!

Ditto, this is actually the other most important use case of angular routing.

My current workaround/solution, for whoever needs it. @mauriciovigolo if you would like a MR, let me know.

Assuming that a route uses lazy load:

1) point to our auth guard in the respective angular route definition

       canLoad: [AuthGuard],
        loadChildren: () => import('./feature/feature.module').then(m => m.FeatureModule)

2) implement CanLoad in the AuthGuard

@Injectable()
export class AuthGuard extends KeycloakAuthGuard implements CanLoad {

    constructor(protected router: Router, protected keycloakAngular: KeycloakService) {
        super(router, keycloakAngular);
    }

    canLoad(route: Route, segments: UrlSegment[]): boolean | Observable<boolean> | Promise<boolean> {
        return new Promise(async (resolve, reject) => {
            try {
                this.authenticated = await this.keycloakAngular.isLoggedIn();
                this.roles = await this.keycloakAngular.getUserRoles(true);

                const result = await this.checkAccessAllowed(route.data);
                resolve(result);
            } catch (error) {
                reject('An error happened during access validation. Details:' + error);
            }
        });
    }

    isAccessAllowed(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean> {
        return this.checkAccessAllowed(route.data);
    }

    checkAccessAllowed(data: Data): Promise<boolean> {
        return new Promise(async (resolve, reject) => {
            if (!this.authenticated) {
                this.keycloakAngular.login().catch(e => console.error(e));
                return reject(false);
            }
            const requiredRoles = data as string[];
            if (!requiredRoles || requiredRoles.length === 0) {
                return resolve(true);
            } else {
                if (!this.roles || this.roles.length === 0) {
                    resolve(false);
                }
                let granted = false;
                for (const requiredRole of requiredRoles) {
                    if (this.roles.indexOf(requiredRole) > -1) {
                        granted = true;
                        break;
                    }
                }
                resolve(granted);
            }
        });
    }
}

Was this page helpful?
0 / 5 - 0 ratings