【问题标题】:AngularJS: Use devise with multiple modelsAngularJS:将设计与多个模型一起使用
【发布时间】:2014-06-02 13:22:15
【问题描述】:

我有一个 Rails 应用程序,它使用了 2 个不同模型对应于截然不同的角色(没有 STI - 完全不同的模型)的设计。

我计划将前端转移到 AngularJS。想知道构建应用程序的最佳方式是什么。

这是我最初的想法:

  1. 每个用户模型都有不同的基础登录页面(domain.com/user 和 domain.com/company)
  2. 在呈现该页面之前,我会使用 devise 检查正确的角色是否已登录,如果没有则重定向到相应的登录页面(服务器端重定向)
  3. 所有未登录的页面都是非 Angular 的,这样才能有效地发生这种情况。
  4. 登录的页面都是 Angular 化的

这确保我不必担心如何让 angular 和 design 协同工作。在一个模块中,我可以确定有一个登录用户(或公司)

如果这听起来不错,请提出建议。

另外,如果有(不太复杂)整个应用程序可以使用 Angular 的方式,我会更喜欢。 (登录重定向到相应的登录页面等)。我已经看到了一些以服务模块等形式使用的 Angular + Devise 示例,但几乎所有这些示例似乎都只适用于一种模型。

编辑:理想情况下,我希望能够尽可能多地使用 Devise 的功能。

【问题讨论】:

    标签: ruby-on-rails angularjs ruby-on-rails-4 devise


    【解决方案1】:

    我建议你重新考虑你的问题,假装设计和角度彼此无关。

    假设你不会在rails中渲染任何html模板。你只是要使用rails创建一个json apihttp://railscasts.com/episodes/350-rest-api-versioning?view=asciicast,应用的接口是将是一个单页的角度应用程序。 UI 路由都将在您的 Angular 应用程序中完成。

    1. 您在 Angular 应用程序中创建了一个登录路由,它有一个指向您服务器的设计登录路由 /api/v1/user/sign-in 的表单。
    2. 当用户在表单上点击提交时,angular 可以进行一些前端验证并将数据发送到您的服务器。
    3. 在您的 Rails 控制器中,devise 将验证此人是谁,在 devise 对其进行身份验证后,您的服务器路由应将用户信息作为 json 响应(或错误消息)发回。

    向您的设计端点发出请求的角度服务现在可以访问用户信息(来自服务器的 json 响应)。它可以检查这个用户对象的属性,比如他们的角色,然后它可以使用 Angular 的定位服务来改变这个角色应该去的地方的路线。

    当路线改变时,角度将呈现路线的视图,一切都会继续进行。

    如果您需要根据角色更改路由中的 UI,请参阅此问题RESTful Authorization in the UI

    当用户稍后返回您的网站时,您可以让 Angular 应用程序检测到他们仍然登录。您为登录用户而写入的 Angular 服务也可以负责尝试获取当前用户,如果没有,则重定向到登录页面。

    Devise 为您提供了一个名为 current_user 的助手,它可以让您访问已登录用户的实例。您应该创建一个类似 /api/v1/current_user 的服务器路由并让它返回用户信息。如果用户已登录,则重定向到他们的主页,就像登录后一样。否则重定向到登录页面。

    如果你不太了解 angular,我建议你花一些时间在这个网站上 https://egghead.io/

    另外你可能需要在服务器上实现授权逻辑http://railscasts.com/episodes/192-authorization-with-cancan

    【讨论】:

    • 正如我所提到的,我有两个不同的 模型,而不是一个模型的两个不同 角色。因此,当用户尝试访问给定的 url 时,我必须执行 => 之类的操作,找出它需要的角色,重定向到相应的登录页面。另外,我有两个不同的登录名。为了提供一些背景信息,我有一个相当大的非 Angular Rails 应用程序,我们正在迁移到 Angular。
    • 在您的 /api/v1/current_user 端点中,您可以返回 current_user || current_company 类似于这个问题stackoverflow.com/questions/10549038/… 你不需要在它返回的json 上有一个角色属性。只要您的角度代码可以从 json 中确定模型的类型,它就可以使用位置服务重定向到正确的 rotue。 Stack Overflow 可能不是您进行广泛架构讨论的最佳选择,也许可以尝试邮件列表groups.google.com/forum/#!forum/rubyonrails-talk
    • 感谢您的提示。也发在那里。我想我大致同意你建议的方法,只是最初设置设计需要我几乎什么都不做来启动它,所以我本质上是在寻找一个选项,我可以在其中尽可能多地利用设计的功能。您的建议有点“从基础开始”,这显然是正确的,但涉及程度略高。
    【解决方案2】:

    构建一个双头身份验证怪物

    所以你描述的是可能的,但肯定会很痛苦。您将不得不构建一堆代码来确定用户是否是 Rails 端的 NormalUser 和 AdminUser。在 Angular 方面,您必须确定用户需要哪个登录名,NormalUser 与 AdminUser。话虽如此,这是可能的,这里有一些应该有所帮助的指针。

    文档是你的朋友

    You really really really want to have a good understanding of how Devise works.Devise 在幕后做了很多魔术。

    要使用Angular 进行身份验证,您需要熟悉$httpProvider.interceptorsServicesResources

    导轨

    路线

    在 Devise 中有两个模型的示例路线:

    devise_for :normal_users
    
    devise_for :admin_users
    
    # route for the sample controller below
    resource :users do
      collection do
        get :current
      end
    end
    

    Devise 带来了什么

    Devise 将在您的控制器中按照以下方式创建 helper methods

    current_normal_user
    
    authenticate_normal_user!
    
    current_admin_user
    
    authenticate_admin_user!
    

    因此,您必须检查两者以查看会话是否已通过身份验证,最好的计划是将两个检查包装到自定义 before_action 中,类似于 before_action :authenticate_all_users

    用户控制器示例

    这是一个示例 UsersControllers,它返回 JSON Angular 将用于检查身份验证。

    class UsersController < ApplicationController
      # Needs a before_action that authenticates the user
    
      respond_to :json
    
      def current
        @user = current_normal_user || current_admin_user
    
        respond_with @user
      end
    
    end
    

    角度

    安全网

    我发现这个拦截器在 Angular 中处理身份验证时非常有用。在设置 Angular 时将此添加到您的 app.config,如果任何 http 请求返回 401 状态代码,它将重定向到指定页面。这比强制所有资源处理用户未通过身份验证的可能性要简单。 (作为咖啡师)

    # Monitors the requests and responses of angular
    #  * Redirects to /users/sign_in if status is a 401
    app.config [
      "$httpProvider"
      ($httpProvider) ->
        $httpProvider.interceptors.push ($q) ->
          request: (config) ->
            config or $q.when(config)
    
          requestError: (rejection) ->
            $q.reject rejection
    
          response: (response) ->
            response or $q.when(response)
    
          responseError: (rejection) ->
    
            # Not logged in, redirect to login
            if rejection.status is 401
              $q.reject rejection
    
               # Change this with desired page
              window.location = "/users/sign_in"
    
            else
              $q.reject rejection
    

    在您的场景中,您可能需要添加逻辑来确定他们应该看到哪个登录页面,normal_user 与 admin_user。

    用户信息

    最后是一个获取用户信息的示例 Angular 服务。如果用户没有被认证,401状态会被之前的$httpProvider捕捉到,对用户进行相应的处理。否则,如果用户通过身份验证,用户的信息将填充到$rootScope.currentUser。您只需将其作为依赖项添加到应受身份验证保护的控制器中。 (在咖啡脚本中)

    angular.module("TheAngularApp.services").service "CurrentUserService", ($rootScope, $http, CurrentUser, User) ->
        userService =
            reloadCurrentUser: ->
                @currentUser = CurrentUser.show((user) ->
                    # set in scope
                    $rootScope.currentUser = user
                )
                @currentUser
    
        userService.reloadCurrentUser()
        userService
    

    此服务依赖于指向 /users/current.json 端点的 CurrentUser 资源。在您使用 CurrentUserService 的场景中,处理多个模型的可能选项是:

    • 检查两次用户是否已通过身份验证,一次用于 normal_user,一次用于 admin_user
    • 创建一个自定义控制器方法来检查 normal_user 和 admin_user 的身份验证,这大致就是示例 rails 控制器正在做的事情。

    额外积分

    或者,我会研究 ng-idle 作为允许会话在 Angular 中过期的一种方式。


    评论更新

    我的登录页面在用户信息的后端请求发生时开始显示,因此重定向到登录页面非常明显并导致用户体验不佳。

    最简单的方法是使用非角度页面进行登录,例如 Devise 提供的页面。一旦用户成功登录,他们被定向到的页面就会加载 Angular 应用程序。这样,您始终可以假设用户在使用 Angular 时已登录。

    如果这不可能,您将不得不从 Angular 发出身份验证请求。这意味着您需要让用户等待,直到您可以从身份验证请求中检查承诺。一旦它有效,您将用户移动到正确的路线。

    警告 我相信如果您登录失败,Devise 会发送一个状态码 401,这将使前面讨论的拦截器跳闸。为了解决这个问题,拦截器必须排除处理身份验证请求的路径。

    处理身份验证的示例资源:

    Session.create {email: email, password: password}, success = (user) ->
       # User was successfully authenticated
       $scope.currentUser = user
       $location.path( "/" );  
    , error = (data, status, headers, config) ->
       # Failed to auth, notify user
    )
    

    【讨论】:

    • 不是确切的答案,但最接近我想要的,因为这个问题是非常开放的。
    • 拦截器信息在我实现这一点时非常有用。一个问题。我的登录页面在用户信息的后端请求发生时开始显示,因此重定向到登录页面非常明显并导致用户体验不佳。想知道何时开始显示页面是否有良好的一般做法,以防止此类问题
    • 最简单的方法是使用非角页面进行登录,例如 Devise 提供的页面。一旦用户成功登录,他们被定向到的页面就会加载 Angular 应用程序。嗯,让我在上面展开。 . .
    • 已经考虑了很多。那里的问题是共享内部链接有问题,因为登录后我无法重定向回它们,因为rails在#之后没有得到部分,我将在登录后重新引导角度模块。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-08
    • 2021-10-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多