angular5 - 角度 5/6 : protect route (route guard) without redirecting to error route

标签 angular5 angular-routing angular6 angular-router-guards

我有一点咸菜。 我正在使用路由保护(实现 CanActivate 接口(interface))来检查用户是否被授予访问特定路由的权限:

const routes: Routes = [
    {
        path: '',
        component: DashboardViewComponent
    },
    {
        path: 'login',
        component: LoginViewComponent
    },
    {
        path: 'protected/foo',
        component: FooViewComponent,
        data: {allowAccessTo: ['Administrator']},
        canActivate: [RouteGuard]
    },
    {
        path: '**',
        component: ErrorNotFoundViewComponent
    }
];

现在它在保护“/protected/foo”路由不被激活方面效果很好,但我想告诉用户他试图访问的路由被禁止(类似于您可能从服务器获得的 403 Forbidden)。

问题: 如何向用户显示这个特殊的错误 View ,而不将他重定向到错误路线,这似乎是我发现的许多来源的首选选项? 我如何仍然使用我的 RouteGuard 而无需实际加载禁止的路线,因为如果我检查 FooViewComponent 内部的访问并显示不同的 View 击败了首先拥有 RouteGuard 的点。

理想情况下,我希望我的 RouteGuard 不仅在 canActivate() 方法中返回 false,而且还用 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;
    }
}

所以我只是阻止路由加载,但我没有重定向。我仅将未登录的访问者重定向到登录路线。

推理:

  • 路线应反射(reflect)特定的应用状态 - 访问路线 url 应重新创建该状态
  • 拥有错误路由(404 Not Found 除外)意味着您的应用程序实际上可以重新创建错误状态。这没有意义 为什么您要将错误状态保留为应用程序的状态?为了 调试目的应该使用日志(控制台或服务器),重新访问 错误页面(即页面刷新)可能会干扰这一点。
  • 此外,通过重定向到错误路线,应用程序应该向用户提供一些错误见解。就此而言,某些参数需要 通过 url 传递或(更糟糕)将错误状态保留在某些错误中 服务并在访问错误路由时检索它。
  • 此外,忽略 RouteGuard 并仅加载组件并检查其内部的访问可能会导致一些额外的依赖项 无论如何都不会使用的已加载(因为不允许用户),使得 整个延迟加载更加困难。

有人对此有某种解决方案吗?我还想知道,为什么 Angular 2+ 出现这么久之后,以前没有人遇到过这种情况?大家都同意重定向吗?

另请记住,虽然我当前正在同步使用 FooViewComponent,但将来可能会发生变化!

最佳答案

我曾经解决过类似的问题。

分享我的stackblitz poc我创建的地方 -

  • 经过身份验证的组件(带防护)
  • 登录组件
  • 权限守卫
  • 路由(/auth 路由由 PermissionGuardService 防护提供)

guard 正在评估用户类型并相应地处理重定向/错误。

用例是 -

  • 用户未登录(显示带有登录消息的 Toast)
  • 用户不是管理员(显示带有未经授权的消息的 Toast)
  • 用户是管理员(显示成功消息的 toast )

我已将用户存储在本地存储中。

EDIT - DEMO enter image description here

如果您需要特殊处理,请告诉我,我将更新代码库。

干杯!

关于angular5 - 角度 5/6 : protect route (route guard) without redirecting to error route,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50477745/

相关文章:

angular - 如何增加嵌套 for 循环的变量计数并打印它

javascript - 错误 : Aws. Translate() 不是构造函数

angular - Ionic 4 - 如何使用 navCtrl 或 Router 服务在页面之间传递数据

Angular 2 : Can't resolve all parameters for Router

angular - 将 Angular 6 升级到 9 的最佳方法是什么?

angular - 在表单错误时触发 Angular 动画

Angular 5 导航

angular - Angular中如何实现多级路由?

javascript - 以 Angular 将文本转换为html格式

javascript - Angular 6中检查可滚动区域是否滚动到最大底部的最佳方法