首页 > 解决方案 > 从 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

标签: ruby-on-rails

解决方案


更新:这个答案已经过时了。在现代版本的导轨中,您应该使用has_secure_token而不是重新发明轮子。

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

首先将列添加到表中:

rails g migration add_access_token_to_captables access_token:string
rails g migrate

然后你想要一个合适的伪随机令牌字符串。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 中处理它更安全,因为您有选择地添加单个异常。

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


推荐阅读