简体   繁体   English

Rails Admin未通过Cancancan或Devise进行身份验证

[英]Rails Admin not authenticating with Cancancan or Devise

I tried this in the config: 我在配置中尝试了这个:

  ### Popular gems integration
  config.authenticate_with do
    warden.authenticate! scope: :user
  end
  config.current_user_method(&:current_user)

here, accessing /admin gets me stuck in a login loop. 在这里,访问/admin会使我陷入登录循环中。 I login then get redirected to the login page. 我登录然后重定向到登录页面。

Previously I had tried 以前我尝试过

class Ability
  include CanCan::Ability

  def initialize(user)
    # Define abilities for the passed in user here. For example:
    #
      user ||= User.new # guest user (not logged in)
      if user.admin?

with the CanCanCan authentication in rails admin config. 在rails admin配置中使用CanCanCan身份验证。 This resulted in user always being nil. 这导致用户始终为零。 Even when I put in 即使我放进去

config.current_user_method(&:current_user)

How do I fix this to authenticate was an admin? 如何解决此问题以验证是否是管理员?

EDIT: in sessions controller 编辑:在会话控制器中

      if user.admin
        redirect_to rails_admin_url
      else
        render json: user
      end

and I get stuck in the redirect back to signin. 而我陷入了重新登录的重定向中。

Routes: 路线:

Rails.application.routes.draw do
  mount RailsAdmin::Engine => '/admin', as: 'rails_admin'
  devise_for :users, controllers: { sessions: :sessions },
                      path_names: { sign_in: :login }
... then many resources lines

EDIT: 编辑:

Sessions Controller: 会话控制器:

class SessionsController < Devise::SessionsController
  protect_from_forgery with: :null_session

  def create
    user = User.find_by_email(sign_in_params[:email])
    puts sign_in_params
    if user && user.valid_password?(sign_in_params[:password])
      user.generate_auth_token
      user.save
      if user.admin
        redirect_to rails_admin_url
      else
        render json: user
      end
    else
      render json: { errors: { 'email or password' => ['is invalid'] } }, status: :unprocessable_entity
    end
  end
end

Rails admin config, trying this: Rails管理员配置,请尝试以下操作:

  ### Popular gems integration
  config.authenticate_with do
    redirect_to merchants_path unless current_user.admin?
  end
  config.current_user_method(&:current_user)

In ApplicationController: 在ApplicationController中:

def current_user
    @current_user ||= User.find(session[:user_id]) if session[:user_id]
  end
  helper_method :current_user

Tried this, current_user is nil. 试过这个,current_user为nil。

You might need to define the after_sign_in_path_for method on the ApplicationController 您可能需要在ApplicationController上定义after_sign_in_path_for方法

By default, it first tries to find a valid resource_return_to key in the session, then it fallbacks to resource_root_path, otherwise it uses the root path. 默认情况下,它首先尝试在会话中找到有效的resource_return_to密钥,然后回退到resource_root_path,否则它将使用根路径。 For a user scope, you can define the default url in the following way: 对于用户范围,可以通过以下方式定义默认url:

get '/users' => 'users#index', as: :user_root # creates user_root_path

namespace :user do
  root 'users#index' # creates user_root_path
end

If the resource root path is not defined, root_path is used. 如果未定义资源根路径,则使用root_path。 However, if this default is not enough, you can customize it, for example: 但是,如果此默认值还不够,则可以对其进行自定义,例如:

def after_sign_in_path_for(resource)
  stored_location_for(resource) ||
    if resource.is_a?(User) && resource.can_publish?
      publisher_url
    else
      super
    end
end

THE CONTROLLER LOGIC FOR REDIRECT 重定向控制器逻辑

The solution from Guillermo Siliceo Trueba will not work with your Users::SessionsController#create action as you are not calling in the parent class create action through the keyword super . Guillermo Siliceo Trueba的解决方案不适用于您的Users::SessionsController#create操作,因为您没有通过关键字super调用父类create操作

The method create from the class Devise::SessionsController will run respond_with in the last line using as location the value returned from after_sign_in_path_for(resource) 该方法create从类Devise::SessionsController运行respond_with使用在上线location ,从返回的值after_sign_in_path_for(resource)

class Devise::SessionsController < DeviseController
  # POST /resource/sign_in
  def create
    self.resource = warden.authenticate!(auth_options)
    set_flash_message!(:notice, :signed_in)
    sign_in(resource_name, resource)
    yield resource if block_given?
    respond_with resource, location: after_sign_in_path_for(resource)
  end
end

I am using this solution in my Users::SessionsController to handle html and json requests and you can implement the same. 我在我的Users::SessionsController使用此解决方案来处理htmljson请求,您可以实现相同的解决方案。

If the controller receives the request with format .json , the code between format.json do .. end is executed, if the request arrives with format.html the parent method is called (I cover all your scenarios). 如果控制器接收到该request与格式.json ,之间的代码format.json do .. end被执行时,如果request与到达format.html父方法被称为(I涵盖所有的场景)。

Rails router identifies the request format from the .json or .html appended at the end of the url (for example GET https://localhost:3000/users.json ) Rails路由器从URL末尾附加的.json.html识别请求格式(例如GET https://localhost:3000/users.json

class Users::SessionsController < Devise::SessionsController
  def create
    respond_to do |format|
      format.json do 
        self.resource = warden.authenticate!(scope: resource_name, recall: "#{controller_path}#new")
        render status: 200, json: resource
      end
      format.html do 
        super
      end
    end
  end
end

The html request will be routed to the super create action . html请求将被路由super创建动作 You just need to override the method def after_sign_in_path_for(resource) from the parent as I am doing in my ApplicationController . 您只需要像我在ApplicationController所做的那样,从父类重写方法def after_sign_in_path_for(resource)

if resource.admin then just return rails_admin_url from this method and skip the other lines, otherwise follow the normal behavior and call super#after_sign_in_path_for(resource) if resource.admin则只需从此方法return rails_admin_url并跳过其他行,否则按照正常行为并调用super#after_sign_in_path_for(resource)

def after_sign_in_path_for(resource)
  return rails_admin_url if resource.admin
  super
end

THE ERROR MESSAGES FOR AUTHENTICATION 认证错误信息

warned.authenticate! will save inside self.resource.errors the error messages. 将保存在self.resource.errors内部的错误消息。 You just need to display the errors on your device using json_response[:error] and manipulating the response in your frontend. 您只需要使用json_response[:error]在设备上显示错误并在前端中处理响应即可。

I am rendering them in the SignInScreen Component 我在SignInScreen组件中渲染它们

在此处输入图片说明

THE TOKEN AUTHENTICATION 令牌认证

user.generate_auth_token
user.save

I use the simple_token_authentication for devise which also allows you to regenerate the token every time the user signs in . 我使用simple_token_authentication进行设计 ,这也使您每次用户登录时都可以重新生成令牌

You just install the gem and add acts_as_token_authenticatable inside your user model . 您只需安装gem并user模型中添加acts_as_token_authenticatable

class User < ApplicationRecord
   acts_as_token_authenticable
end

You pass headers X-User-Email and X-User-Token with the corresponding values as explained in their guide . 您按照标头指南中的说明传递标头X-User-EmailX-User-Token

Other alternatives to simple_token_authentication simple_token_authentication其他替代方法

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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