Angular 6-基于角色/声明的身份验证防护不起作用

时间:2018-08-13 08:19:45

标签: angular routing jwt auth-guard

我的应用程序中经过身份验证的用户可以具有多个角色,因此,我想根据用户的特定角色来保护路由。我在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] }
    ]
  }

auth-guard-service:

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);
  }

2 个答案:

答案 0 :(得分:0)

我有同样的问题。您可以尝试以下

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

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

答案 1 :(得分:0)

请参见stackblitz

中的示例

在您的app-routing.module.ts

remDr$navigate("https://...")
remDr$refresh()

在您的RoleGuardService中

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

在UserRolesService中

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) );
  }
}

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

希望这会有所帮助。