【问题标题】:Getting ng-token-auth to work with devise_token_auth让 ng-token-auth 与 devise_token_auth 一起工作
【发布时间】:2015-02-25 04:34:01
【问题描述】:

我有一个 Rails 和 Ionic 项目。后端使用 devise_token_auth Gem,前端使用 ng-token-auth;这些应该“无缝”工作。

就注册和登录而言,我已经完成了所有工作,这将返回一个有效的响应对象。但是,在我使用 $state.go('app.somepage') 之后的任何进一步请求都会导致 401 Unauthorized 响应。

我感觉我实际上并没有将令牌存储在任何地方。有人可以帮忙吗?

这里有一些sn-ps:

    .controller('LoginCtrl',['$scope', '$auth', '$state', function($scope, $auth, $state) {
    $scope.loginForm = {}
    $scope.handleLoginBtnClick = function() {
      console.log($scope.loginForm);
      $auth.submitLogin($scope.loginForm)
          .then(function(resp) {
            $state.go('app.feed');
          })
          .catch(function(resp) {
            console.log(resp.errors);
          });
    };

状态定义:

    .state('app', {
  url: "/app",
  abstract: true,
  templateUrl: "templates/menu.html",
  controller: 'AppCtrl',
  resolve: {
    auth: function($auth) {
      return $auth.validateUser();
    }
  }

})

资源:

factory('Post', ['railsResourceFactory', 'apiUrl', function (railsResourceFactory, apiUrl) {
    return railsResourceFactory({
        url: apiUrl + '/posts',
        name: 'post'
    });
}]).

在 PostsCtrl 中:

  $scope.loadFeed = function() {
    Post.query().then(function (posts) {
      $scope.posts = posts;
    }, function (error) {
      console.log( 'Did not get posts!'); ### THIS FIRES
    }).finally(function() {
      // Stop the ion-refresher from spinning
      $scope.$broadcast('scroll.refreshComplete');
    });
  };

登录响应对象:

{"data":{"id":1,"provider":"email","uid":"1234","phone":null,"name":"Admin","image":null,"username":"admin"}}

ApplicationController 顶部:

class ApplicationController < ActionController::Base
  include DeviseTokenAuth::Concerns::SetUserByToken

  before_filter :add_allow_credentials_headers
  before_filter :cors_preflight_check
  after_filter :cors_set_access_control_headers
  before_action :configure_permitted_parameters, if: :devise_controller?

  ..yadayada...

  def configure_permitted_parameters
    devise_parameter_sanitizer.for(:sign_up) << :phone
    devise_parameter_sanitizer.for(:sign_up) << :username
    devise_parameter_sanitizer.for(:sign_up) << :session

    devise_parameter_sanitizer.for(:sign_in) << :phone
    devise_parameter_sanitizer.for(:sign_in) << :username
    devise_parameter_sanitizer.for(:sign_in) << :session
  end

还有一些默认的用户模型。

Rails 日志:

Started GET "/posts" for 192.168.83.26 at 2015-02-24 23:29:02 -0500
Processing by PostsController#index as JSON
  Parameters: {"post"=>{}}
Filter chain halted as :authenticate_user! rendered or redirected
Completed 401 Unauthorized in 1ms (Views: 0.2ms | ActiveRecord: 0.0ms)

如果有人能提供一些见解,那就太好了。我很乐意根据需要发布更多 sn-ps。

【问题讨论】:

  • 我还没有阅读你的整个问题,但是我用 Lynn Dylan Hurley 的库写了一篇关于 Rails/Angular 身份验证的完整文章。 airpair.com/ruby-on-rails/posts/…
  • 另外,我不知道你的问题的答案,但在你的情况下我会做的只是启动一个空白的新项目并按照我的教程,看看它是否有效。然后,如果教程有效,看看你的项目和教程有什么不同。
  • 这个项目进展如何?我在做一些非常相似的事情并且遇到了问题,你开源了吗?
  • 不,但是如果您阅读下面我选择的答案,那应该会给您一个线索。我不允许开源代码。 :(

标签: ruby-on-rails angularjs devise ionic


【解决方案1】:

事实证明,解决方案相当简单。似乎在每个人提供的大多数示例中,他们都忽略了允许 access-token 以及所有其他 CORS 标头。

我们为此使用了 rack-cors,在 config.ru 的底部:

require 'rack/cors'
use Rack::Cors do

  # allow all origins in development
  allow do
    origins '*'
    resource '*',
             :headers => :any,
             :expose  => ['access-token', 'expiry', 'token-type', 'uid', 'client'],
             :methods => [:get, :post, :delete, :put, :options]
  end
end

然后在ApplicationController.rb中:

  before_filter :add_allow_credentials_headers
  skip_before_filter :verify_authenticity_token
  before_filter :cors_preflight_check
  after_filter :cors_set_access_control_headers


  def cors_set_access_control_headers
    headers['Access-Control-Allow-Origin'] = '*'
    headers['Access-Control-Allow-Methods'] = 'POST, GET, PUT, DELETE, OPTIONS'
    headers['Access-Control-Allow-Headers'] = 'Origin, Content-Type, Accept, Authorization, Token'
    headers['Access-Control-Max-Age'] = '1728000'
  end

  def cors_preflight_check
    if request.method == 'OPTIONS'
      headers['Access-Control-Allow-Origin'] = '*'
      headers['Access-Control-Allow-Methods'] = 'POST, GET, PUT, DELETE, OPTIONS'
      headers['Access-Control-Allow-Headers'] = 'X-Requested-With, X-Prototype-Version, Token'
      headers['Access-Control-Max-Age'] = '1728000'

      render :text => '', :content_type => 'text/plain'
    end
  end

  def add_allow_credentials_headers
    # https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#section_5
    #
    # Because we want our front-end to send cookies to allow the API to be authenticated
    # (using 'withCredentials' in the XMLHttpRequest), we need to add some headers so
    # the browser will not reject the response
    response.headers['Access-Control-Allow-Origin'] = request.headers['Origin'] || '*'
    response.headers['Access-Control-Allow-Credentials'] = 'true'
  end

【讨论】:

  • 不知道为什么这没有得到任何投票或基本文档中没有涵盖。这对我来说是必须的,我认为我们没有做任何不寻常的事情。
  • 同意。我不知道没有这个怎么可能工作。虽然我只需要 allow 块,但不需要 ApplicationController 的东西。此外,如果您使用的是 Rails,则允许块可以进入您的 application.rb 而不是 config.ru。
  • 谢谢。我看到这对很多人来说都是一个问题。我选择了自己的答案,因为它实际上是解决方案,我认为您的最后评论是相关的。我们使用了千斤顶的方法。感谢 config.ru 中代码的提示。
  • 大家好,我遇到了完全相同的问题(离子,没有访问令牌标头),这些解决方案没有帮助。任何想法将不胜感激!
【解决方案2】:

此信息可能与您有关。

jwako/ionic_rails_sample

【讨论】:

    【解决方案3】:

    就我而言,我使用 cookie 来存储令牌。并且每当我们在 Angular 应用程序中执行 $auth 方法时,一些方法将尝试转到您在 Rails 路由器中定义的设计路由,并匹配/验证存储在任何标头请求中的令牌。 (每次您尝试执行 http 请求时!使用浏览器检查器检查您的请求标头,如果它们包含 uidauth_token,如果您要通过 GET 验证 /validate_token (https://github.com/lynndylanhurley/devise_token_auth#usage-tldr))

    由于您没有提及您的路线,我们可以假设/auth

    $auth 提供的那些$http 请求应该包含要通过Rails 的设计进行身份验证的令牌,并在我们执行$auth.submitLogin() 时将其捕获并存储到浏览器的cookie 中。

    这是我之前的项目中它是如何工作的示例。

    app.factory('authInterceptor', ['$q', 'ipCookie', '$location',  function($q, ipCookie, $location) {
      return {
        request: function(config) {
          config.headers = config.headers || {};
          if (ipCookie('access-token')) {
            config.headers['Access-Token'] = ipCookie('access-token');
            config.headers['Client'] = ipCookie('client');
            config.headers['Expiry'] = ipCookie('expiry');
            config.headers['Uid'] = ipCookie('uid');
          }
          return config;
        },
        responseError: function(response) {
          if (response.status === 401) {
            $location.path('/login');
            ipCookie.remove('access-token');
          }
          return $q.reject(response);
        }
      };
    }])
    

    并将令牌格式设置为如下所示(或根据需要自定义)

    $authProvider.configure({
      tokenValidationPath: '/auth/validate_token',
      signOutUrl: '/auth/sign_out',
      confirmationSuccessUrl: window.location.href,
      emailSignInPath: '/auth/sign_in',
      storage: 'cookies',
      tokenFormat: {
        "access-token": "{{ token }}",
        "token-type": "Bearer",
        "client": "{{ clientId }}",
        "expiry": "{{ expiry }}",
        "uid": "{{ uid }}"
      }
    });
    

    不要忘记向 Interceptor 注入 ipCookie(查找 angular-cookie 而不是 angular-cookies),因为这是 ng-token-auth 用于 cookie 管理的 cookie 库。

    如果我说得不够清楚,请在下面提出问题。 :D

    【讨论】:

    • 谢谢,成功了。此外,我们使用本地存储来存储令牌,这同样有效。
    • 我可以验证此解决方案是否有效。我也在使用本地存储。
    【解决方案4】:

    也许为时已晚,

    但问题在于您无法在 cookie 上进行身份验证(仅限 Android)。因此,您可以尝试使用 localStorage 来保存会话信息(在 iOS 和 Android 上)

    例如

    .config(function($authProvider) {
      $authProvider.configure({
        apiUrl: 'http://myprivateapidomain/api',
        storage: 'localStorage'
      });
    })
    

    您可以在文档的具体问题中阅读更多内容:https://github.com/lynndylanhurley/ng-token-auth/issues/93

    【讨论】:

    • 我们最初是这样做的,但并没有解决问题。它只允许我们存储一些会话信息并假装已经进行了身份验证。无论如何,令牌的整个想法正是使用会话数据。这是针对不同问题的不同解决方案。
    【解决方案5】:

    有点晚了,但对于任何可能尝试在 Ionic 应用程序中使用 ng-token-auth 的人来说,我为使其工作(就我而言)所做的就是为我的模块设置下一个配置:

    app.config(['$httpProvider', function($httpProvider) {  
        $httpProvider.defaults.withCredentials = true;
    
      }]);
    

    (我没有在我的 http 请求中发送任何 cookie)

    【讨论】:

      【解决方案6】:

      您是否尝试过为 $authProvider 添加配置。这个例子在https://github.com/lynndylanhurley/devise_token_auth的自述文件中。

      angular.module('myApp', ['ng-token-auth'])
        .config(function($authProvider) {
          $authProvider.configure({
            apiUrl: 'http://api.example.com'
            authProviderPaths: {
              github: '/auth/github' // <-- note that this is different than what was set with github
            }
          });
        });
      

      【讨论】:

      • 是的,谢谢,身份验证最初有效,但随后无法转换为后续页面请求。
      【解决方案7】:

      我怀疑您尝试登录的用户无效。发生这种情况时,授权标头为空,并且不会在响应中发回访问令牌。

      这发生在这里:https://github.com/lynndylanhurley/devise_token_auth/blob/0d4de71/app/controllers/devise_token_auth/concerns/set_user_by_token.rb#L53

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-04-25
        • 2016-03-12
        • 2018-08-31
        • 1970-01-01
        • 2015-05-10
        相关资源
        最近更新 更多