0

我的应用程序中经过身份验证的用户可以有多个角色,因此,我想根据用户的特定角色来保护路由。checkAuthentication()我在方法中包含角色检查AuthGuardService,然后data: { roles: ['USER'] }在路由模块中应用。我还设置identity了存储来检测AuthService. 但是,当我尝试登录时,它不会路由到仪表板,而是停留在登录页面,即使我可以看到本地存储中设置的令牌。

路由模块:

  {
    path: 'home', component: HomeComponent, canActivate: [AuthGuardService], data: { roles: ['PRIMARY, SUBSTITUTE'] },
    children: [
      { path: '', redirectTo: 'offers', pathMatch: 'full' },
      { path: 'offers', component: OffersComponent, data: { roles: ['PRIMARY, SUBSTITUTE'] }, canActivateChild: [AuthGuardService] },
      { path: 'users', component: UsersComponent, data: { roles: ['PRIMARY'] }, canActivateChild: [AuthGuardService] },
      { path: 'settings', component: SettingsComponent, data: { roles: ['PRIMARY, SUBSTITUTE, USER'] },
        canActivateChild: [AuthGuardService] }
    ]
  }

身份验证服务:

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
    const url: string = state.url;
    return this.checkAuthentication(url, state, route.data['roles']);
  }

  canActivateChild(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
    return this.canActivate(route, state);
  }

  checkAuthentication(url: string, state, requiredRoles: string[]) {
    return this.authService.roles$.pipe(
      flatMap((roles: string[]) => {
        for (const role of requiredRoles) {
          if (roles.includes(role) && this.authService.hasValidToken()) {
            return of(true);
          } else if (roles.includes(role) && this.authService.hasValidToken() === false) {
            return this.authService.refreshToken().pipe(
              map((tokens: AuthToken) => {
                if (tokens.authToken) {
                  // refresh token successful
                  return true;
                }
                // refresh token did not succeed
                this.authService.logout();
                this.router.navigate(['']);
                return false;
              },
                error => {
                  this.authService.logout();
                  this.router.navigate(['']);
                  return of(false);
                })
            );
          }
        }
        this.router.navigate(['']);
        return of(false);
      })
    );
  }

身份验证服务:

private roles = new BehaviorSubject([]);
  public roles$ = this.roles.asObservable();

  private identity = new BehaviorSubject(<Identity>{});
  public identity$ = this.identity.asObservable();

  constructor(
    private store: Store<AppState>
  ) {
    this.store.select('tokens').subscribe((tokens: AuthToken) => {
      this.tokens = tokens;
    });

    this.store.select('identity').subscribe((identity: any) => {
      console.log(identity);
      if (identity.identity && identity.identity.roles) {
        this.setIdentity(identity.identity);
        this.setRoles(identity.identity.roles);
      } else {
        this.setRoles([]);
      }
    });
  }

  setRoles(roles: any[]) {
    this.roles.next(roles);
    console.log(roles);
  }

  setIdentity(identity: Identity) {
    this.identity.next(identity);
    console.log(identity);
  }
4

2 回答 2

1

请参阅stackblitz中的此示例

在你的 app-routing.module.ts

const routes: Routes = [
   {
       path: "admin",
       component: AdminOnlyComponent,
       canActivate: [RoleGuardService],
       data: { roles: ['admin']}
   },
   ...
}

在您的 RoleGuardService

import { Injectable } from '@angular/core';
import { UserRolesService} from './user-roles.service';
import { Router, ActivatedRouteSnapshot } from '@angular/router';
@Injectable({
  providedIn: 'root'
})
export class RoleGuardService {

  constructor(private getUserRoles: UserRolesService) { }

  canActivate(route: ActivatedRouteSnapshot): boolean {
    return route.data.roles.some( ai => this.getUserRoles.getRoles().includes(ai) );
  }
}

在用户角色服务中

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class UserRolesService {
   userRoles: string[] = [];

  constructor() { }

  setRoles(Roles: string[]){
    this.userRoles = Roles.slice(0);
  }

  getRoles(){
    return this.userRoles;
  }
}

在用户登录系统时设置角色或从您的本地存储中获取这些角色...。

希望这会有所帮助..

于 2019-11-01T03:41:00.567 回答
0

我遇到过同样的问题。您可以尝试以下方法

  1. 复制令牌并在此处检查https://jwt.io/并验证令牌是否包含您期望的角色(区分大小写)。

  2. 而且,当你有多个角色时,它出现在一个数组中,但当它是单个角色时,它是一个字符串。

于 2019-04-18T04:21:43.823 回答