gpt4 book ai didi

ruby-on-rails - Devise_token_auth 和 Devise 使用用户名和电子邮件登录

转载 作者:数据小太阳 更新时间:2023-10-29 07:40:06 28 4
gpt4 key购买 nike

在尝试向我现有的 Rails 应用程序添加 token 身份验证时,我不断遇到错误,它源于设计 authentication_keys。在我的 Rails 4 应用程序中,我允许用户使用用户名或电子邮件登录,我想为 API 提供相同的功能。

我从API登录时得到的错误如下

Started POST "/api/v1/auth/sign_in" for 127.0.0.1 at 2016-04-19 23:40:26 -0400
Processing by DeviseTokenAuth::SessionsController#create as JSON
Parameters: {"login"=>"email@example.com", "password"=>"[FILTERED]", "session"=>{"login"=>"email@example.com", "password"=>"[FILTERED]"}}
Can't verify CSRF token authenticity
Geokit is using the domain: localhost
User Load (1.3ms) SELECT "users".* FROM "users" WHERE (login = 'email@example.com' AND provider='email') ORDER BY "users"."id" ASC LIMIT 1
SQLite3::SQLException: no such column: login: SELECT "users".* FROM "users" WHERE (login = 'email@example.com' AND provider='email') ORDER BY "users"."id" ASC LIMIT 1
Completed 500 Internal Server Error in 5ms

SQLite3::SQLException - no such column: login:

用户模型的代码如下。问题源于用户负载,因为它没有将登录参数转换为通过电子邮件(或用户名)进行搜索。但是下面的代码对于常规的设备登录来说完全可以正常工作。

#User.rb
devise :database_authenticatable, :registerable, :confirmable,
:recoverable, :rememberable, :trackable, :validatable, :authentication_keys => [:login]
include DeviseTokenAuth::Concerns::User

def self.find_for_database_authentication(warden_conditions)
conditions = warden_conditions.dup
if login = conditions.delete(:login)
where(conditions.to_h).where(['lower(username) = :value OR lower(email) = :value', { :value => login.downcase }]).first
else
where(conditions.to_h).first
end
end

感谢您的帮助或指导!

编辑将参数作为电子邮件和密码发送时,也会出现错误。

Processing by DeviseTokenAuth::SessionsController#create as JSON
Parameters: {"email"=>"email@example.com", "password"=>"[FILTERED]", "session"=>{"email"=>"email@example.com", "password"=>"[FILTERED]"}}
Can't verify CSRF token authenticity
Unpermitted parameters: email, format, session
Completed 401 Unauthorized in 49ms (Views: 0.3ms | ActiveRecord: 0.0ms | Solr: 0.0ms)

最佳答案

  1. 来自 Devise doc ,您需要执行以下操作:

    • app/models/user.rb

      attr_accessor :login
    • config/initializers/devise.rb

      Devise.setup do |config|
      config.authentication_keys = [:login]
      config.case_insensitive_keys = [:login]
      end
  2. devise_token_auth 未维护 ( cf unmerged PR ),因此与 Devise 不同步,这就是您需要覆盖 SessionsController 的原因:

    • config/routes.rb

      Rails.application.routes.draw do
      namespace :api do
      scope module: :v4 do
      mount_devise_token_auth_for "User", at: "auth", controllers: {
      sessions: "api/v4/devise_token_auth/sessions"
      }
      end
      end
      end
    • app/controllers/api/v4/devise_token_auth/sessions_controller.rb

      module Api
      module V4
      module DeviseTokenAuth
      class SessionsController < ::DeviseTokenAuth::SessionsController
      def create
      # Check
      field = (resource_params.keys.map(&:to_sym) & resource_class.authentication_keys).first

      @resource = nil
      if field
      q_value = resource_params[field]

      if resource_class.case_insensitive_keys.include?(field)
      q_value.downcase!
      end

      q = "#{field.to_s} = ? AND provider='email'"

      if ActiveRecord::Base.connection.adapter_name.downcase.starts_with? "mysql"
      q = "BINARY " + q
      end

      # LOG IN BY EMAIL AND USERNAME
      if field == :login
      @resource = resource_class.where("email = ? OR username = ?", q_value, q_value).first
      else
      @resource = resource_class.where(q, q_value).first
      end
      # LOG IN BY EMAIL AND USERNAME END
      end

      if @resource && valid_params?(field, q_value) && (!@resource.respond_to?(:active_for_authentication?) || @resource.active_for_authentication?)
      valid_password = @resource.valid_password?(resource_params[:password])
      if (@resource.respond_to?(:valid_for_authentication?) && !@resource.valid_for_authentication? { valid_password }) || !valid_password
      render_create_error_bad_credentials
      return
      end
      # create client id
      @client_id = SecureRandom.urlsafe_base64(nil, false)
      @token = SecureRandom.urlsafe_base64(nil, false)

      @resource.tokens[@client_id] = {
      token: BCrypt::Password.create(@token),
      expiry: (Time.now + ::DeviseTokenAuth.token_lifespan).to_i
      }
      @resource.save

      sign_in(:user, @resource, store: false, bypass: false)

      yield @resource if block_given?

      render_create_success
      elsif @resource && !(!@resource.respond_to?(:active_for_authentication?) || @resource.active_for_authentication?)
      render_create_error_not_confirmed
      else
      render_create_error_bad_credentials
      end
      end
      end
      end
      end
      end
  3. 测试例子

    resource "User sign in" do

    let(:user) { build(:user) }

    before(:each) do
    user.create_new_auth_token
    end

    post "/api/auth/sign_in" do
    parameter :email, "Email address"
    parameter :password, "Password for user"

    it "fails with incorrect login and password" do
    do_request(login: "user.does.not@exist.com", password: "wrong_password")
    expect(status).to eq(401)
    expect(JSON.parse(response_body)["errors"])
    .to include("Invalid login credentials. Please try again.")
    end

    it "logs in with correct username and password" do
    user.save!
    do_request(login: user.username, password: user.password)
    expect(status).to eq(200)
    expect(JSON.parse(response_body)["data"]["email"]).to include(user.email)
    end

    it "logs in with correct email and password" do
    user.save!
    do_request(login: user.email, password: user.password)
    expect(status).to eq(200)
    expect(JSON.parse(response_body)["data"]["email"]).to include(user.email)
    end
    end
    end

关于ruby-on-rails - Devise_token_auth 和 Devise 使用用户名和电子邮件登录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36733524/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com