Flo*_*ock 4 ruby-on-rails ruby-on-rails-4
我正在尝试在我的Rails API上实现基于令牌的基本身份验证.它适用于现有路线,但这里有一个问题:
当未经身份验证的用户访问不存在的路由时,它会显示该404 - Not found页面,而不是401 - Unauthorized.在验证路由之前,如何让Rails检查身份验证?
这是我的application_controller.rb:
class Api::V1::ApiController < ApplicationController
# Main controller inherited by all API controllers
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :null_session
# Enforce site-wide authentication
before_action :authenticate
def authenticate
authenticate_token || render_unauthorized
end
def authenticate_token
# Can we find a user with the authentication token used?
authenticate_with_http_basic do |u, p|
# Only search active, private keys
@api_key = ApiKey.active.find_by(api_key: u, is_secret: true)
@user = @api_key.user if @api_key
return @api_key
end
end
def render_unauthorized
# Displays the Unauthorized message
render json: JSON.pretty_generate({
error: {
type: "unauthorized",
message: "This page cannot be accessed without a valid API key."
}
}), status: 401
end
end
Run Code Online (Sandbox Code Playgroud)
可以这样想:有人阻止你在办公室询问方向.你是否要求他们先提供一些身份证,或者你只是按照他们的方式出示?
如果它是一个公职,我只是告诉他们的方式..但如果我们在美国中央情报局的限制特别项目科,我不在乎你要去的地方(甚至 特别是如果你告诉我你"重新寻找Office 404,我知道它不存在):我想先看一些ID.
我最初提到了基于令牌的身份验证,但它实际上是Basic Auth(带有"username"="token").
使用内置的rails认证你无法实现你想要的,因为@ rich-peck解释道.Rails首先评估您的路由,然后传递控制器的请求.
你有两个选择.首先,做一下Stripe的人正在做的事情.将身份验证委派给应用服务器前面的Web服务器(在其情况下为nginx).
$ curl -I https://api.stripe.com/this/route/doesnt/exist
HTTP/1.1 401 Unauthorized
Server: nginx
Date: Fri, 08 Aug 2014 21:21:49 GMT
Content-Type: application/json;charset=utf-8
Www-Authenticate: Basic realm="Stripe"
Cache-Control: no-cache, no-store
Stripe-Version: 2014-08-04
Strict-Transport-Security: max-age=31556926; includeSubDomains
Run Code Online (Sandbox Code Playgroud)
或者,如果您希望/需要将其保存在ruby-land中,您可以使用机架中间件,在rails加载您的路线之前进行身份验证.您可以尝试https://github.com/iain/rack-token_auth
$ bin/rake middleware
...snip a bunch of middleware...
use Rack::TokenAuth
run Dummy::App::Application.routes
Run Code Online (Sandbox Code Playgroud)
更新:使用HTTP基本身份验证
在这种情况下,您根本不需要另一个库,因为机架通过Rack::Auth::Basic中间件内置了对http basic auth的支持,例如
config.middleware.use Rack::Auth::Basic do |username, password|
username == "bob" && password == "secret"
end
Run Code Online (Sandbox Code Playgroud)
更新:我可以将身份验证应用于API命名空间吗?
这取决于.由于机架中间件在rails加载路由,控制器等之前运行,因此它不知道您的命名空间.尽管如此,如果您的命名空间控制器也在URL级别命名空间,例如全部在命名空间/api,您可以检查request.path是否应用身份验证.
您可以创建一个新的机架middlware来装饰 Rack::Auth::Basic这种行为,例如
class MyAPIAuth < Rack::Auth::Basic
def call(env)
request = Rack::Request.new(env)
if request.path =~ /\A\/api\/?/
super
else
@app.call(env)
end
end
end
# change your configuration to use your middleware
config.middleware.use MyAPIAuth do |username, password|
username == "bob" && password == "secret"
end
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3095 次 |
| 最近记录: |