【问题标题】:Devise Json Authentication设计 Json 身份验证
【发布时间】:2015-02-15 12:33:57
【问题描述】:

我正在用 Rails 编写应用程序的后端。当我在后端工作时,我需要给前端开发人员一个 REST API 来开始构建前端。最终,前端和后端将一起驻留在一个应用程序中,但目前它们是分开的。

暂时我已经在我的应用程序中启用了跨域资源共享,方法是在ApplicationController 中添加以下内容:

config.action_dispatch.default_headers.merge!({
                                                  'Access-Control-Allow-Origin' => '*',
                                                  'Access-Control-Request-Method' => '*'
                                              });

目前,我还通过将以下内容添加到 application.rb 来关闭 CSRF 令牌:

skip_before_filter :verify_authenticity_token

我正在使用 Devise 对用户进行身份验证。为了让 Devise 能够处理 JSON 请求,我做了以下工作:

devise.rb

config.navigational_formats = ['*/*', :html, :json]

routes.rb

devise_for :users, :controllers => {:omniauth_callbacks => "omniauth_callbacks", :sessions => 'sessions', :registrations => 'registrations' }

我的SessionsController

class SessionsController < Devise::SessionsController
  #todo had to do following to support logging in through ajax. need to add logic to send back error response when login fails.
  #todo see  http://stackoverflow.com/questions/5973327/using-devise-1-3-to-authenticate-json-login-requests/8402035#8402035 and
  #todo https://web.archive.org/web/20130928040249/http://jessehowarth.com/devise
  #todo see http://stackoverflow.com/questions/11277300/devise-failure-authentication-via-json-sends-back-html-instead-of-json
  def create
    respond_to do |format|
      format.html { super }
      format.json {
        resource = warden.authenticate!(:scope => resource_name, :recall => "#{controller_path}#failure")
        sign_in(resource_name, resource)
        return render :json => {:success => true, :user => resource}
      }
    end
  end

  def destroy
    respond_to do |format|
      format.html { super }
      format.json {
        Devise.sign_out_all_scopes ? sign_out : sign_out(resource_name)
        render :json => {}
      }
    end
  end

  def failure
    render :json => {:success => false, :errors => ["Login Failed"]}, :status => 422
  end
end

我有一个扩展的 Devise 的 RegistrationsController 以及在 routes.rb 中指出的,但我不在这里发布它的内容,因为我认为它与这个问题无关。

通过上述设置,我可以使用 user[email] 和 user[password] 参数向“/users/sign_in”发送 ajax 请求,并让用户登录。响应如下所示:

{
 success: true 
 user: { 
  authentication_token: "SNa2kPqkm5ENsZMx7yEi"
  created_at: "2014-12-16T02:40:39.179Z"
  email: "xyz@xyz.com"
  id: 99999
  name: null
  provider: null
  uid: null
  updated_at: "2014-12-17T02:29:31.537Z"
 }
}

现在如何使用我在登录响应中收到的 authentication_token 向其他需要用户身份验证的控制器操作发送请求?我是否需要在请求标头中设置此令牌?我无法找到有关如何使用此令牌的信息。请帮忙。

【问题讨论】:

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


    【解决方案1】:

    似乎按照此处的要点所述,答案是您将用户的电子邮件和 authetication_token 与每个请求一起发送到后端。您可以选择在请求标头中发送它或仅作为参数发送。您只需修改检查电子邮件和令牌的方法,并相应地在 ApplicationController 中登录用户。这是我的 ApplicationController(我现在将电子邮件和令牌作为请求中的参数发送):

    class ApplicationController < ActionController::Base
      # Prevent CSRF attacks by raising an exception.
      # For APIs, you may want to use :null_session instead.
      protect_from_forgery with: :exception
      #todo remove this once ui is integrated. following turns off the csrf token:
      skip_before_filter :verify_authenticity_token
    
      #todo begin code to support authentication using token
      # This is our new function that comes before Devise's one
      before_filter :authenticate_user_from_token!
      # This is Devise's authentication
      before_filter :authenticate_user!
    
      private
    
      def authenticate_user_from_token!
        user_email = params[:user_email].presence
        user       = user_email && User.find_by_email(user_email)
    
        # Notice how we use Devise.secure_compare to compare the token
        # in the database with the token given in the params, mitigating
        # timing attacks.
        if user && Devise.secure_compare(user.authentication_token, params[:user_token])
          sign_in user, store: false
        end
      end
      #todo end code to support authentication using token
    end
    

    我忘记在我的帖子中提到我已经添加了迁移以将 authentication_token 列添加到用户模型。此外,我必须在 User 模型中添加以下内容(如要点中所述),以便在每次创建/更新用户时生成身份验证令牌:

    #todo begin code to support ajax authentication of users
      #todo see https://gist.github.com/josevalim/fb706b1e933ef01e4fb6
      # You likely have this before callback set up for the token.
      before_save :ensure_authentication_token
    
      def ensure_authentication_token
        if authentication_token.blank?
          self.authentication_token = generate_authentication_token
        end
      end
    
      private
    
      def generate_authentication_token
        loop do
          token = Devise.friendly_token
          break token unless User.where(authentication_token: token).first
        end
      end
      #todo end code to support  ajax authentication of users
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-03-25
      • 2020-08-28
      • 2012-02-09
      • 2014-11-15
      • 1970-01-01
      • 2011-11-28
      • 2015-05-04
      相关资源
      最近更新 更多