【问题标题】:How can I display an error page for unauthorised access in Angular?如何在 Angular 中显示未经授权访问的错误页面?
【发布时间】:2019-01-24 00:23:27
【问题描述】:

我正在 Angular 应用程序中处理 authz。我们大量使用路由,因此在路由守卫中检查授权似乎很有意义。

我在canActivateChild 路由中执行此操作,设置大致如下:

class MyGuard implements CanActivateChild {
    canActivateChild(route, state) {
      return !route.data || route.data.active;
    }
}

const routes: Routes = [
  {
    path: '',
    canActivate: [MyGuard],
    canActivateChild: [MyGuard],
    children: [
      {
        path: 'hello', component: HelloComponent, data: { active: false }
      }
    ]
  }
]

(这显然被大大简化了,但我认为我如何确定路由是否被授权的细节并不相关。更完整的工作示例在 StackBlitz 上https://stackblitz.com/edit/dv-so-angular-route-authz

我的问题是,当授权失败时,路由守卫只让我做两件事:返回false 并完全取消导航并保持在原始路线上;或重定向到其他 URL。

我想要的 UI 显示一条错误消息,但在用户尝试导航到的 URL 下。 (即,如果这是设置权限的错误,用户更容易报告“嘿,我无法访问此 URL”,然后重新加载页面。)实际上,我希望服务器返回 HTTP 403 状态有身体。

我考虑过不对路线进行检查,而是让目标组件本身显示其他内容。不过,我并不是特别喜欢这个,如果没有其他原因它会干扰模块的按需加载。有没有一种“干净”的方法可以从路由器做到这一点?

【问题讨论】:

    标签: angular typescript authorization


    【解决方案1】:

    我知道这不是您正在等待的回应,但我质疑这个原则。 Angular 中的路由确保一个重要的不变量始终为真:路由中使用的组件是通过路由表给出的。这就是为什么你找不到一个简单的方法来做你计划的事情。

    我的猜测是,与这一原则的不同之处在于要求未来的可维护性和/或可靠性问题。

    我认为可以解决您最初的以下愿望:您将失败的请求路由到 the/initial/path/failed,并且此路由的组件包含可能对 IT 团队有用的错误数据。

    然后,在the/initial/path/failed 路由中,放置一个反向保护:如果权限正常,则重定向到the/initial/path

    这样,您就不会破坏路由世界核心的 Angular 不变量。

    这个过程类似于未登录时回滚到登录页面,如果已经登录则跳过登录页面。

    编辑: 我在 cmets 中看到了你的观点,我大多同意你的看法。 尽管如此,为了尝试推进解决方案,这里有一个可接受的无样板近似值:

    您创建了一个简单的“失败”组件。它显示了从服务中获取的消息(经典的组件间消息传递,类似于 Flash 消息功能)。在你的保护下:

    router.navigate(...).then(_ =>
      Service.post_flash_message('instructions with "retry" link to initial url'));
    

    不完全是您的要求,但迈出了一步。

    【讨论】:

    • 这确实不是我要找的答案。我正在为用户构建应用程序,而不是为框架作者。我需要一个比模糊的“这可能会导致问题”更强烈的警告——你编写的每一行代码可能。据我所知,Ng 路由不允许像 **/failed 这样的路由,所以你的方法似乎会涉及很多样板,这几乎不是维护的好处。
    • 我还认为所谓的与登录用户的相似性不太合适。未经身份验证的用户可能会采取措施来纠正这一点 - 登录 - 这就是为什么他们会绕道进入登录页面并返回。对于未经授权的用户,他们可能不会采取任何行动,他们要么访问他们不应该访问的资源,要么管理员必须授予他访问权限;他们从一开始就处于死胡同,所以增加更多的步骤是没有意义的。
    • 好的。如果有帮助,请用其他想法编辑我的答案。虽然我不太同意框架。当你选择一个自以为是的框架时,你会遵守规则,或者开辟一些困难的道路。这不是事实,而是经验,我同意它不是 100% 的时间有效。但是我发现当我陷入这种状态时,框架中通常有一个可以接受的解决方案。你可以肯定地从 A 开车到 B 只能倒车,但这将是一场地狱般的旅程:)
    【解决方案2】:

    再补充一个想法:你考虑过在守卫中返回一个新的 observable 吗? Angular 守卫可以返回booleanObservable<boolean>。这样,您可以通过在拒绝路由导航之前显示带有错误/警告消息的模式来延迟实际路由过程。

    可以这样实现:

    class MyGuard implements CanActivateChild {
        canActivateChild(route, state): boolean | Observable<boolean> {
          if (!route.data || route.data.active) {
            // TODO: return your modal observable here and map it to boolean, e.g. via:
            return modalService.alert('Data error').map(() => false);
          }
          return true;
        }
    }
    

    我实际上在我的应用程序中使用了这种模式来允许用户在模式中更新他们的令牌/登录(如果守卫检测到令牌已过期,这很可能会导致服务器 API 错误),然后继续导航获得新令牌后。守卫将“悬空”直到 observable 发出 truefalse

    【讨论】:

    • 如果用户只是冷导航到未经授权的 URL,比如在新标签页中打开链接,这会怎样?我们确实有一个 toast 通知实用程序,但我真的不知道 Ng 是否渲染了任何东西。我会保留这个技巧,但我必须强调这是授权,而不是身份验证。用户无需在应用程序 UI 中执行任何操作即可获得对资源的访问权,如果他应该拥有它,管理员将必须授予他适当的角色,并且用户将不得不重新加载以加载新功能无论如何。
    猜你喜欢
    • 1970-01-01
    • 2010-12-26
    • 2010-12-02
    • 1970-01-01
    • 2019-07-17
    • 1970-01-01
    • 2015-08-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多