You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Rails 5.1.4与Puma 3.11.0,Heroku环境内容密码保护方案咨询

Hey there! Let's figure out how to password-protect your public Rails content without breaking all those internal links. Since moving everything to controllers isn't feasible, here are a few practical solutions tailored to your Rails 5.1.4 + Puma 3.11.0 + Heroku stack:

方案1:全局HTTP Basic Auth(最简单推荐)

This is the quickest way to lock down your entire app without touching existing controllers or routes. It uses Rack's built-in auth middleware, which works seamlessly with Heroku.

  1. Add an initializer for auth
    Create config/initializers/basic_auth.rb with this code:
if Rails.env.production?
  # Insert the auth middleware before static file handling to protect assets too
  Rails.application.config.middleware.insert_before ActionDispatch::Static, Rack::Auth::Basic, "Internal Protected Area" do |username, password|
    # Validate credentials against Heroku environment variables
    username == ENV["BASIC_AUTH_USER"] && password == ENV["BASIC_AUTH_PASSWORD"]
  end
end
  1. Set environment variables on Heroku
    Run these commands in your terminal:
heroku config:set BASIC_AUTH_USER=your_preferred_username
heroku config:set BASIC_AUTH_PASSWORD=a_secure_password_here

That's it! Every request (including static assets and internal links) will prompt for the username/password before accessing content. No changes to your existing routes or controllers needed.

方案2:带路径排除的HTTP Basic Auth

If you need to leave certain paths public (like robots.txt or a public API endpoint), adjust the middleware to skip auth for those routes:

Update config/initializers/basic_auth.rb:

if Rails.env.production?
  Rails.application.config.middleware.insert_before ActionDispatch::Static, Rack::Auth::Basic, "Internal Protected Area" do |username, password|
    # Skip auth for specific paths
    skip_paths = ["/robots.txt", "/public-api"]
    next true if skip_paths.include?(request.path)

    username == ENV["BASIC_AUTH_USER"] && password == ENV["BASIC_AUTH_PASSWORD"]
  end
end
方案3:自定义会话式登录(适合友好界面)

If you want a custom login page instead of the browser's default auth prompt, you can build a session-based system using a Rack middleware (still no changes to your existing controllers):

  1. Create a custom auth middleware
    Make app/middlewares/auth_middleware.rb:
class AuthMiddleware
  def initialize(app)
    @app = app
  end

  def call(env)
    request = Rack::Request.new(env)
    
    # Skip auth for login/logout paths and authenticated sessions
    if request.path.in?(["/login", "/logout"]) || request.session[:authenticated]
      @app.call(env)
    else
      # Redirect unauthenticated GET requests to login page
      if request.get?
        [302, {"Location" => "/login", "Content-Type" => "text/plain"}, ["Redirecting to login..."]]
      else
        # Block non-GET requests with 401
        [401, {"Content-Type" => "text/plain"}, ["Unauthorized: Please login first"]]
      end
    end
  end
end
  1. Register the middleware
    Add this to config/initializers/middleware.rb:
if Rails.env.production?
  Rails.application.config.middleware.use AuthMiddleware
end
  1. Add a simple sessions controller
    Create app/controllers/sessions_controller.rb:
class SessionsController < ApplicationController
  def new
    # Login page view
  end

  def create
    if params[:username] == ENV["AUTH_USER"] && params[:password] == ENV["AUTH_PASSWORD"]
      session[:authenticated] = true
      # Redirect back to the page the user was trying to access
      redirect_to request.referer || root_path
    else
      flash[:error] = "Invalid username or password"
      render :new
    end
  end

  def destroy
    session[:authenticated] = nil
    redirect_to root_path
  end
end
  1. Add routes for login/logout
    Update config/routes.rb:
get "/login", to: "sessions#new"
post "/login", to: "sessions#create"
delete "/logout", to: "sessions#destroy"
  1. Create a login view
    Make app/views/sessions/new.html.erb with your custom login form:
<h1>Please Login</h1>
<% if flash[:error] %>
  <p style="color: red;"><%= flash[:error] %></p>
<% end %>
<%= form_tag login_path do %>
  <div>
    <%= label_tag :username %>
    <%= text_field_tag :username %>
  </div>
  <div>
    <%= label_tag :password %>
    <%= password_field_tag :password %>
  </div>
  <div>
    <%= submit_tag "Login" %>
  </div>
<% end %>
  1. Set environment variables on Heroku
heroku config:set AUTH_USER=your_username
heroku config:set AUTH_PASSWORD=your_secure_password

This approach gives users a nicer login experience while keeping all your existing internal links intact.


For most cases, 方案1 is the best fit—it's minimal, secure, and requires almost no code changes. All these solutions work with your Rails 5.1.4 and Puma setup, and deploy smoothly to Heroku.

内容的提问来源于stack exchange,提问作者Mark Fraser

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:10:48