HTTP 令牌身份验证
简单令牌示例
class PostsController < ApplicationController
TOKEN = "secret"
before_action :authenticate, except: [ :index ]
def index
render plain: "Everyone can see me!"
end
def edit
render plain: "I'm only accessible if you know the password"
end
private
def authenticate
authenticate_or_request_with_http_token do |token, options|
# Compare the tokens in a time-constant manner, to mitigate
# timing attacks.
ActiveSupport::SecurityUtils.secure_compare(token, TOKEN)
end
end
end
这是一个更高级的 Token
示例,其中只有 Atom 源和 XML API
受 HTTP 令牌身份验证保护。常规 HTML 界面受会话方法保护
class ApplicationController < ActionController::Base
before_action :set_account, :authenticate
private
def set_account
@account = Account.find_by(url_name: request.subdomains.first)
end
def authenticate
case request.format
when Mime[:xml], Mime[:atom]
if user = authenticate_with_http_token { |t, o| @account.users.authenticate(t, o) }
@current_user = user
else
request_http_token_authentication
end
else
if session_authenticated?
@current_user = @account.users.find(session[:authenticated][:user_id])
else
redirect_to(login_url) and return false
end
end
end
end
在集成测试中,可以执行类似以下操作
def test_access_granted_from_xml
authorization = ActionController::HttpAuthentication::Token.encode_credentials(users(:dhh).token)
get "/notes/1.xml", headers: { 'HTTP_AUTHORIZATION' => authorization }
assert_equal 200, status
end
在共享主机上,Apache 有时不会将身份验证标头传递给 FCGI 实例。如果你的环境符合此描述并且无法进行身份验证,请在 Apache 设置中尝试此规则
RewriteRule ^(.*)$ dispatch.fcgi [E=X-HTTP_AUTHORIZATION:%{HTTP:Authorization},QSA,L]
- A
- E
- P
- R
- T
常量
AUTHN_PAIR_DELIMITERS | = | /(?:,|;|\t)/ |
TOKEN_KEY | = | "token=" |
TOKEN_REGEX | = | /^(Token|Bearer)\s+/ |
实例公共方法
authenticate(controller, &login_procedure) 链接
如果存在令牌授权标头,则使用当前令牌和选项调用登录过程。
如果找到令牌,则返回 login_procedure
的返回值。如果找不到令牌,则返回 nil
。
参数
-
controller
- 当前请求的ActionController::Base
实例。 -
login_procedure
- 如果存在令牌,则调用 Proc。Proc 应采用两个参数authenticate(controller) { |token, options| ... }
来源:显示 | 在 GitHub 上
# File actionpack/lib/action_controller/metal/http_authentication.rb, line 466 def authenticate(controller, &login_procedure) token, options = token_and_options(controller.request) unless token.blank? login_procedure.call(token, options) end end
authentication_request(controller, realm, message = nil) 链接
设置 WWW-Authenticate 头,让客户端知道需要令牌。
不返回任何内容。
参数
-
controller
-ActionController::Base
对于传出响应的实例。 -
realm
-String
在头中使用的领域。
来源:显示 | 在 GitHub 上
# File actionpack/lib/action_controller/metal/http_authentication.rb, line 550 def authentication_request(controller, realm, message = nil) message ||= "HTTP Token: Access denied.\n" controller.headers["WWW-Authenticate"] = %(Token realm="#{realm.tr('"', "")}") controller.__send__ :render, plain: message, status: :unauthorized end
encode_credentials(token, options = {}) 链接
来源:显示 | 在 GitHub 上
# File actionpack/lib/action_controller/metal/http_authentication.rb, line 535 def encode_credentials(token, options = {}) values = ["#{TOKEN_KEY}#{token.to_s.inspect}"] + options.map do |key, value| "#{key}=#{value.to_s.inspect}" end "Token #{values * ", "}" end
params_array_from(raw_params) 链接
获取 raw_params
并将其转换为参数数组。
来源:显示 | 在 GitHub 上
# File actionpack/lib/action_controller/metal/http_authentication.rb, line 501 def params_array_from(raw_params) raw_params.map { |param| param.split %r/=(.+)?/ } end
raw_params(auth) 链接
此方法获取授权主体并通过 AUTHN_PAIR_DELIMITERS
中定义的标准化 :
、;
或 \t
分隔符拆分键值对。
来源:显示 | 在 GitHub 上
# File actionpack/lib/action_controller/metal/http_authentication.rb, line 516 def raw_params(auth) _raw_params = auth.sub(TOKEN_REGEX, "").split(WHITESPACED_AUTHN_PAIR_DELIMITERS) _raw_params.reject!(&:empty?) if !_raw_params.first&.start_with?(TOKEN_KEY) _raw_params[0] = "#{TOKEN_KEY}#{_raw_params.first}" end _raw_params end
rewrite_param_values(array_params) 链接
这将删除包装值的 "
字符。
来源:显示 | 在 GitHub 上
# File actionpack/lib/action_controller/metal/http_authentication.rb, line 506 def rewrite_param_values(array_params) array_params.each { |param| (param[1] || +"").gsub! %r/^"|"$/, "" } end
token_and_options(request) 链接
从令牌授权标头中分析令牌和选项。Authorization 标头中的值应带有前缀 "Token"
或 "Bearer"
。如果标头如下所示
Authorization: Token token="abc", nonce="def"
则返回的令牌为 "abc"
,选项为 {nonce: "def"}
。
如果存在令牌,则返回 [String, Hash]
的 Array
。如果未找到令牌,则返回 nil
。
参数
-
request
- 具有当前标头的ActionDispatch::Request
实例。
来源:显示 | 在 GitHub 上
# File actionpack/lib/action_controller/metal/http_authentication.rb, line 488 def token_and_options(request) authorization_request = request.authorization.to_s if authorization_request[TOKEN_REGEX] params = token_params_from authorization_request [params.shift[1], Hash[params].with_indifferent_access] end end
token_params_from(auth) 链接
来源:显示 | 在 GitHub 上
# File actionpack/lib/action_controller/metal/http_authentication.rb, line 496 def token_params_from(auth) rewrite_param_values params_array_from raw_params auth end