Iva*_*jak 11 angular-routing angular-router-guards angular5 angular6
我有一点泡菜.我正在使用Route guard(实现CanActivate接口)来检查用户是否被授予访问特定路由的权限:
const routes: Routes = [
{
path: '',
component: DashboardViewComponent
},
{
path: 'login',
component: LoginViewComponent
},
{
path: 'protected/foo',
component: FooViewComponent,
data: {allowAccessTo: ['Administrator']},
canActivate: [RouteGuard]
},
{
path: '**',
component: ErrorNotFoundViewComponent
}
];
Run Code Online (Sandbox Code Playgroud)
现在它可以很好地保护'/ protected/foo'路由不被激活,但我想告诉用户他试图访问的路由是禁止的(类似于你可能从服务器获得的403 Forbidden).
问题:
如何向用户显示此特殊错误视图,而不将其重定向到错误路径哪个接缝是我找到的众多来源的首选选项?
而且如何在RouteGuard没有实际加载禁止路线的情况下仍然使用我,因为如果我检查我的内部访问FooViewComponent并显示不同的视图它首先会失败点RouteGuard.
理想情况下,我想让我RouteGuard不仅在canActivate()方法中返回false ,而且还完全用say替换组件ErrorForbiddenViewComponent.但我不知道该怎么做,或者事件是否可能.任何替代品?
这就是我的护卫队现在的样子:
import {Injectable} from '@angular/core';
import {Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot} from '@angular/router';
import {AuthService} from '../services/auth.service';
@Injectable()
export class RouteGuard implements CanActivate {
constructor(
private router: Router,
private auth: AuthService
) {}
canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
const { auth, router } = this;
const { allowAccessTo } = next.data;
const identity = auth.getIdentity();
if (
identity &&
allowAccessTo.indexOf(identity.role)
) {
// all good, proceed with activating route
return true;
}
if (identity) {
// TODO show ErrorForbiddenViewComponent instead of redirecting
console.log('403 Forbidden >>', next);
}
else {
// not logged in: redirect to login page with the return url
const [returnUrl, returnQueryParams] = state.url.split('?');
console.log('401 Unauthorised >>', returnUrl, returnQueryParams, next);
router.navigate(['/login'], {queryParams: {returnUrl, returnQueryParams}});
}
return false;
}
}
Run Code Online (Sandbox Code Playgroud)
所以我只是阻止路由加载,但我没有重定向.我只将未登录的访问者重定向到登录路由.
推理:
有没有人有这种解决方案?我也想知道在Angular 2+出现这么长时间以后没有人遇到这种情况之后怎么样?每个人都可以重定向吗?
还要记住,虽然我目前正在使用FooViewComponent同步,但未来可能会有所改变!
我曾经研究过类似的问题。
分享我创建的stackblitz poc -
/auth路线设有PermissionGuardService警卫)守卫正在评估用户类型并相应地处理重定向/错误。
用例是 -
shows a toast with log in message)shows a toast with unauthorised message)show a toast with success messaage)我已将用户存储在本地存储中。
如果您需要特殊处理,请告诉我,我将更新代码库。
干杯!
在查看了Tarun Lalwani 在问题评论中提供的angular2 示例并深入研究了Angular 文档上的动态组件加载器文章后,我成功地将其应用到我的代码中:
RouteGuard我在指定路线时不再使用 my :
{
path: 'protected/foo',
component: FooViewComponent,
data: {allowAccessTo: ['Administrator']}, // admin only
canActivate: [RouteGuard]
},
Run Code Online (Sandbox Code Playgroud)
相反,我创建了特殊的RouteGuardComponent,以下是我如何使用它:
{
path: 'protected/foo',
component: RouteGuardComponent,
data: {component: FooViewComponent, allowAccessTo: ['Administrator']}
},
Run Code Online (Sandbox Code Playgroud)
这是代码RouteGuardComponent:
@Component({
selector: 'app-route-guard',
template: '<ng-template route-guard-bind-component></ng-template>
// note the use of special directive ^^
})
export class RouteGuardComponent implements OnInit {
@ViewChild(RouteGuardBindComponentDirective)
bindComponent: RouteGuardBindComponentDirective;
// ^^ and here we bind to that directive instance in template
constructor(
private auth: AuthService,
private route: ActivatedRoute,
private componentFactoryResolver: ComponentFactoryResolver
) {
}
ngOnInit() {
const {auth, route, componentFactoryResolver, bindComponent} = this;
const {component, allowAccessTo} = route.snapshot.data;
const identity = auth.getIdentity();
const hasAccess = identity && allowAccessTo.indexOf(identity.role);
const componentFactory = componentFactoryResolver.resolveComponentFactory(
hasAccess ?
component : // render component
ErrorForbiddenViewComponent // render Forbidden view
);
// finally use factory to create proper component
routeGuardBindComponentDirective
.viewContainerRef
.createComponent(componentFactory);
}
}
Run Code Online (Sandbox Code Playgroud)
另外,这需要定义特殊指令(我确信这可以通过其他方式完成,但我刚刚应用了 Angular 文档中的动态组件示例):
@Directive({
selector: '[route-guard-bind-component]'
})
export class RouteGuardBindComponentDirective {
constructor(public viewContainerRef: ViewContainerRef) {}
}
Run Code Online (Sandbox Code Playgroud)
它不是我自己问题的完整答案(但它是一个开始),所以如果有人提供更好的东西(即仍然使用的方法canActivate和延迟加载的能力),我将确保考虑到这一点。