3

我试图找到一种方法来router-outlet根据用户的角色有条件地渲染子路由中的组件。

例如,我有一个 DashboardComponent,其中包含一个router-outlet. 我希望在 child 中呈现的组件router-outlet根据用户角色而有所不同,该角色由令牌传入,而无需指定其他路由。

我希望尝试在接近此的地方编写我的路线:

{ 
    path: 'dashboard', 
    component: DashboardComponent,
    children: [
        { path: '', component: DataViewsComponent }, // For standard user role
        { path: '', component: AdminViewsComponent } // For the admin user role
    ]
}

这种确切的模式当然行不通,因为路由器只看到两条相同的路由路径。

我设法编写了一个服务,该服务使用该canActivate属性来检查用户的角色并根据角色转发到不同的路由:

@Injectable()
export class RoleRouteRedirectService implements CanActivate {

    roleRoutingPermissions: any = {
        // Will contain redirects for every route in the app
        // For this example, only contains reroutes for the dashboard route
        ['dashboard']: [
            { roles: [ 'user' ], redirect: '/dashboard/admin' },
            { roles: [ 'admin' ], redirect: '/dashboard/admin' }

        ]
    };

    constructor(private router: Router) {}

    canActivate(route: ActivatedRouteSnapshot): boolean {
        // In the larger app, the roles are taken out of the token
        // Here I've mocked them from localStorage for ease
        const userRoles: string[] = localStorage.getItem('user-role').split(',');
        const url: string = route.data.url;

        // Find the object property matching the desired origin URL
        if (url in this.roleRoutingPermissions) {
            // Iterate over the array of route permissions in this property
            for (const item of roleRoutingPermissions[url]) {
                // If we find the entry for the role, apply the redirect
                if (item.roles.some(role => userRoles.includes(role))) {
                    this.router.navigate([ item.redirect ]);

                    return false;
                }
            }
        }

        // Otherwise, fail
        console.log('Could not find matching route permissions');
        return false;

    }

}

这将采用不同的 Routes 模式:

{ 
    path: 'dashboard',
    component: DashboardComponent,
    canActivate: [ RoleRouteRedirectService ],
    data: {
        url: 'dashboard'
    },
    // Conditional Routes
    children: [
        {
            path: 'user',
            component: DataViewsComponent,
        },
        {
            path: 'admin',
            component: AdminHomeComponent,
        }
    ]
}

现在,这真的很好用。但是,我对这种模式有以下问题:

  1. 我想避免有额外的路线 - 即我不想要dashboard/user,我只想dashboard为不同的用户呈现不同的孩子
  2. 我可以看到这将很快导致我的路线,并且 RoleRouteRedirectService 随着应用程序的增长变得非常复杂
  3. 这感觉不是使用路由保护的正确方法(如果我错了,请纠正我!)
  4. 我觉得必须有一种方法可以从我缺少的路由器内部处理这个问题

如果有人有任何想法,我很想听听他们的意见。我很欣赏这是一个相对复杂的问题 - 如果我错过了任何有用的信息,请发表评论,我会看看可以添加什么。

4

2 回答 2

4

另一种方法是创建一个同时包含 theDataViewsComponentAdminHomeComponent. 根据用户的角色,可以通过ngIf. 然后你可以从你RoleRouteRedirectService的这个父组件中移动逻辑:

<DataViewsComponent *ngIf="user.hasRole('user')"></DataViewsComponent>
<AdminHomeComponent *ngIf="user.hasRole('admin')"></DataViewsComponent>
于 2018-08-17T11:44:42.390 回答
0

Angular 路由器使用first-match-wins定义路由的策略,结合canActivateIMO 对您的用例来说是一个可行的策略。我不认为这种方法有什么问题。这是我实现路由的方式:

const routes: Routes = [
  { path: '', component: HomeComponent },
  { path: 'logout', component: HomeComponent  },
  { path: '', component: AuthorizedComponent, canActivate: [AuthGuard], children: [
    { path: 'onboard', component: OnboardComponent, canActivate: [AuthGuard]  },
    { path: 'onboard_requests', component: OnboardRequestsComponent, canActivate: [AuthGuard]  },
    { path: 'employee_list', component: EmployeeListComponent, canActivate: [AuthGuard]  },
    { path: 'employee_detail', component: EmployeeDetailComponent, canActivate: [AuthGuard]  }
  ]
}]

尽管您的用例似乎与我的略有不同,但正如您所见,我使用了两个组件HomeComponentAuthorizedComponent基于canActivate根路径

于 2018-09-25T04:41:58.977 回答