简体   繁体   中英

Rails : Devise with config.session_store :disabled

I am building a RESTful API that is stateless with Rails 3 and the gem devise .

Since I don't want to store any session, I have disabled them by defining in config/initializers/session_store.rb :

MyApp::Application.config.session_store :disabled

All my Warden Strategies (http basic auth, token auth) don't store any information ( stored? returns false).

I am using in my controllers the helper authenticate_user! as a before_filter. I obtain the following error during the authentication:

NoMethodError (undefined method `[]' for nil:NilClass) :
warden (1.2.1) lib/warden/session_serializer.rb:32:in `fetch'
warden (1.2.1) lib/warden/proxy.rb:212:in `user'
warden (1.2.1) lib/warden/proxy.rb:318:in `_perform_authentication'    
warden (1.2.1) lib/warden/proxy.rb:127:in `authenticate!'
devise (2.2.3) lib/devise/controllers/helpers.rb:48:in `authenticate_user!'

The code in session_serializer at line 32 is the following method:

def fetch(scope)
  key = session[key_for(scope)] # it crashes here
  return nil unless key

  method_name = "#{scope}_deserialize"
  user = respond_to?(method_name) ? send(method_name, key) : deserialize(key)
  delete(scope) unless user
  user
end

It crashes because session (ie @env['rack.sessions']) equals nil (session_store is indeed disabled). This is a default call, the strategies have not been called yet.

Since I don't want to monkey patch, I am looking for a good way to achieve this with session_store disabled.

Thanks

If you are open to dropping devise, I'd suggest authenticating with a token. Token authentication can be quickly set-up in rails and validate requests by passing a token into each request header.

Authorization : Token token="xxx"

I've tacked on my default Rails api token authentication code if you are interested.

class ApplicationController < ActionController::Base
  protect_from_forgery


  private
  def restrict_access
    authenticate_with_http_token do |token, options|
      User.exists?(authentication_token: token)
    end
  end

  private
  def api_user
    authenticate_with_http_token do |token, options|
      User.find_by_authentication_token(token)
    end
  end
end

class UsersController < ApplicationController
  before_filter :restrict_access, :except => ['create']

  def create
    user=User.create(:email=>params[:email],
                     :password=>params[:password],
                     :password_confirmation=>params[:password_confirmation])

  end
end

class TokensController < ApplicationController
  respond_to :json

  def create
  user = User.authenticate(params[:email],params[:password])
  if user
    render :json => User.find_by_email(params[:email])
  else
    render :json => "#{params[:email]} not authorized.", :status => 401
  end
end

class User < ActiveRecord::Base

  attr_accessible :email, :authentication_token
  attr_accessor :password, :password_confirmation

  def self.authenticate(email, password)
    user= find_by_email(email)
    user && user.password_hash == BCrypt::Engine.hash_secret(password, user.password_salt) ? user : nil
  end
  private
  def generate_authentication_token
    begin
      self.authentication_token = SecureRandom.hex
    end while self.class.exists?(authentication_token: authentication_token)
    self.last_sign_in_at=DateTime.now
    self.sign_in_count=self.sign_in_count+1
  end

  private
  def encrypt_password
    if password.present?
      self.password_salt = BCrypt::Engine.generate_salt
      self.password_hash = BCrypt::Engine.hash_secret(password,password_salt)
    end
  end
end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM