1

Rails 3 と gem でステートレスな RESTful API を構築していますdevise

セッションを保存したくないので、で定義して無効にしましたconfig/initializers/session_store.rb

MyApp::Application.config.session_store :disabled

すべての Warden 戦略 (http 基本認証、トークン認証) は情報を保存しません ( stored?false を返します)。

コントローラーでヘルパーauthenticate_user!を before_filter として使用しています。認証中に次のエラーが表示されます。

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!'

32 行目の session_serializer のコードは、次のメソッドです。

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

session(つまり、@env['rack.sessions']) が nil に等しい (session_store が実際に無効になっている)ため、クラッシュします。これはデフォルトの呼び出しで、戦略はまだ呼び出されていません。

私はモンキー パッチを適用したくないので、session_store を無効にしてこれを実現する良い方法を探しています。

ありがとう

4

1 に答える 1

1

デバイスをドロップしても構わない場合は、トークンで認証することをお勧めします。トークン認証は Rails ですばやくセットアップでき、トークンを各リクエスト ヘッダーに渡すことでリクエストを検証できます。

認可 : トークン token="xxx"

興味があれば、デフォルトの Rails api トークン認証コードを追加しました。

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
于 2013-05-14T22:50:12.353 に答える