在Rails中进行Http基本身份验证

38

你好,我来自Grails背景,新学习Rails。我希望在Rails中进行HTTP基本身份验证。

我有一段Grails代码可以进行基本身份验证,像这样:

def authString = "${key}:".getBytes().encodeBase64().toString()
def conn = "http://something.net".toURL().openConnection()
conn.setRequestProperty("Authorization", "Basic ${authString}")

同样的事情能用Rails实现吗?

9个回答

96
在您想要使用基本HTTP身份验证限制的控制器中编写以下代码。
class ApplicationController < ActionController::Base
  http_basic_authenticate_with :name => "user", :password => "password" 
end

使用open-uri发起请求的方法类似于以下代码:

require 'open-uri'

open("http://www.your-website.net/", 
  http_basic_authentication: ["user", "password"])

8
【对下投票感到好奇】写我说的话不是一个好习惯吗? - Nishant

22
在Ruby on Rails 4中,您可以根据上下文轻松地应用基本的HTTP身份验证来实现全站身份验证或每个控制器的身份验证。
例如,如果您需要进行全站身份验证:
class ApplicationController < ActionController::Base
  http_basic_authenticate_with name: "admin", password: "hunter2"
end

或者基于每个控制器的情况:

class CarsController < ApplicationController
  http_basic_authenticate_with name: "admin", password: "hunter2"
end

5
hunter2?这是一个较老的互联网迷因,但它仍然有效。 - boyd

12

我赞成@Nishant的答案,但又想添加一些小贴士。您可以通过传递 only except 来设置过滤器,以便它仅适用于特定的控制器操作,如下所示:

http_basic_authenticate_with name: "admin", password: "strongpasswordhere", only: [:admin, :new, :edit, :destroy]

或者

http_basic_authenticate_with name: "admin", password: "strongpasswordhere", except: [:show]

许多情况下都非常有帮助。


8
# app/controllers/application_controller.rb
  before_filter :http_basic_auth

  def http_basic_auth
    if ENV['HTTP_AUTH'] =~ %r{(.+)\:(.+)}
      unless authenticate_with_http_basic { |user, password|  user == $1 && password == $2 }
        request_http_basic_authentication
      end
    end
  end

然后,您只需要使用用户:密码导出环境变量,例如:

   export HTTP_AUTH=user:pass

如果您正在使用heroku.com:

   heroku config:set HTTP_AUTH=user:pass

2
连接到受基本HTTP身份验证保护的HTTP端点时,我通常使用HTTPartyHTTParty是对较低级别的Ruby STD类(如net/http)的简单包装器。
使用基本身份验证的HTTParty的示例用法。
class Delicious
  include HTTParty
  base_uri 'https://api.del.icio.us/v1'

  def initialize(u, p)
    @auth = {username: u, password: p}
  end

  def recent options={}
    options.merge!({basic_auth: @auth})
    self.class.get('/posts/recent', options)
  end
end

delicious = Delicious.new("<username>", "<password>")

pp delicious.recent #=> list of recent elements

检查更多在GitHub上的例子

2

2
以上答案是正确的,但最好不要在源代码中放置用户和密码。生产环境中最好将密码存储在环境变量中(在开发过程中可以将密码存储在代码中)。
class YourController..
  http_basic_authenticate_with name: ENV["HTTP_BASIC_AUTH_USER"], password: ENV["HTTP_BASIC_AUTH_PASSWORD"], if: -> { ENV['RAILS_ENV'] == 'production' }
  http_basic_authenticate_with name: "user", password: "pass", if: -> { ENV['RAILS_ENV'] != 'production' }

1

针对最新的Rails版本,有一个ASCIIcast视频,详细讲解了HTTP基本身份验证的步骤。

链接在这里here

顺便提一下:请注意,HTTP基本身份验证会以明文形式传输用户名和密码,因此您不应将此方法用于需要更高安全级别的应用程序。


2
如果您使用https URL向带有HTTP基本身份验证的网站发出请求,那么标头仍将被加密,对吗? - Kelsey Hannan

0

您可以使用request.basic_auth来传递所需的基本身份验证参数。根据需要,可以更改content_type

您将需要包括 -

require 'net/http'
require 'uri'

请求代码将如下所示 -

  key = "awknfkjn93013nksdkjnsd09920930jwkslkd102"
  token = "qs90si90w4jm309w0kd5009kdw700i29012dfmk"
  uri = URI("http://something.net")
  request = Net::HTTP::Post.new(uri)
  request.content_type = 'application/x-www-form-urlencoded'
  request.basic_auth(key, token)
  payload = {
              your_payload_key=> "your_payload_value"
            }
  request.set_form_data(payload)
  request_options = {
      use_ssl: uri.scheme == "https"
  }
  response = Net::HTTP.start(uri.hostname, uri.port, request_options) do |http|
    http.request(request)
  end

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接