从Rails应用程序为“公共”链接生成新路由

时间:2018-11-17 15:41:39

标签: ruby-on-rails

我正在尝试建立一个“公共”链接,该链接可以使某人无需登录/未经授权即可访问我的应用程序的特定页面。

对于解决此问题的最佳方法,我有些困惑,因此需要一些建议。

要开始使用,我已经在要建立链接(random_id)的对象表中添加了Captable

我现在正在努力的是:我应该构建一个全新的控制器(例如PublicCaptableController)并查看此公共链接,以便我可以控制该“公共查看器”看到的内容吗?还是有任何更简便的方法可以使用现有的CaptablesController创建新视图,以提供我可以使用现有控制器控制的一组选定信息?

我的一个主意是使用以下命令编辑application_controller.rb

before_action :authenticate_user!, unless: -> params[:random_id].present?

但是,这感觉像是相当大的安全风险。我如何以一种简单但更有效/安全的方式做到这一点?

感谢任何指导/帮助!

这是我的routes.rb文件。

Rails.application.routes.draw do

  devise_for :users
  get '/landing', :to => redirect('/landing.html')
  root 'companies#index'
  post "companies/switch_current_company_context" => "companies#switch_current_company_context"

  resources :companies do
    resources :shareholders
    resources :captables do
      post :subscribe_to_captable
      resources :events do
        post :lock_event
        post :unlock_event
        resources :transactions
      end
    end
  end
end
CaptablesController的

片段

class CaptablesController < ApplicationController
  before_action :set_company
  before_action :set_captable, only: [:show, :edit, :update, :destroy]

  def index
    @captables = @company.captables
  end

  def show
    @captable = Captable.find(params[:id])
  end

ApplicationController的代码段

class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception, unless: -> { request.format.json? }
  before_action :authenticate_user!

  def after_sign_in_path_for(resource_or_scope)
    # Set a default current company scope for a use after signing in
    session[:current_company] = current_user.companies.first.id unless current_user.companies.empty?
    puts session[:current_company]
    companies_path

  end

end

1 个答案:

答案 0 :(得分:1)

您可以向模型添加一个简单的访问令牌,并在通过查询字符串传递时绕过授权/身份验证。

首先将列添加到表中:

rails g migration add_access_token_to_captables access_token:string
rails g migrate

然后,您需要一个合适的psuedorandom令牌字符串。 Ruby Stdlib包含一个涵盖您的SecureRandom模块。

SecureRandom.hex(10) #=> "52750b30ffbc7de3b362"

让我们设置模型回调以在创建时生成随机令牌:

class Captable < ApplicationRecord
  # ...
  after_validation :set_access_token!, if: :new_record?

  private


  def set_access_token!
    self.access_token = loop do
      random_token = SecureRandom.hex(10)
      break random_token unless self.class.exists?(access_token: random_token)
    end
  end
end

然后,您可以使用令牌有条件地跳过回调:

class CaptablesController
  skip_before_action :authenticate_user, if: :has_valid_access_token?, only: :show

  private
    def has_valid_access_token?
      params[:access_token].present? && Captable.exists?(params.permit(:access_token, :id))
    end
end

这比在ApplicationController中处理它更安全,因为您有选择地添加了一个异常。

这是一种更简单的方法,该方法使用单个令牌使任何人都可以访问单个资源。您还可以通过创建一个单独的表并在使用后销毁它们并使它们无效来创建一次性令牌。