如何在用户未授权时使用 Devise 发送 CORS 头信息(401 响应)

18

我正在开发一个应用程序,服务器和调用API的客户端位于不同的域下,因此我想使用CORS。为此,我必须在服务器响应中设置相应的HTTP标头:

def cors_set_access_control_headers
  headers['Access-Control-Allow-Origin'] = 'http://localhost'
  headers['Access-Control-Allow-Methods'] = 'POST, GET, OPTIONS'
  headers['Access-Control-Allow-Headers'] = '*, X-Requested-With, X-Prototype-Version, X-CSRF-Token, Content-Type'
  headers['Access-Control-Max-Age'] = "1728000"
end
这个方法用作ApplicationController中的before_filter
对于某些资源,用户必须经过身份验证和授权才能访问。请求通过XHR / Ajax完成。因此,如果用户未经身份验证,则Devise会向客户端发送401响应,而不是重定向到登录页面。但是,设置CORS标头的过滤器不适用于该响应。因此,401响应未发送到客户端。我想在客户端捕获并使用401响应。
目前,我正在使用一个解决方法,即不使用Devise身份验证方法,而是使用自定义身份验证片段:
def authenticate_cors_user
  if request.xhr? && !user_signed_in?
    error = { :error => "You must be logged in." }
    render params[:format].to_sym => error, :status => 401
  end
end

这也被设置为before_filterApplicationController中。这样就会触发设置CORS头的过滤器,一切都正常工作。

我更喜欢使用Devise的默认行为,但CORS头必须在401响应中设置。如何做到这一点?我需要为此配置warden吗?

如何为Devise生成的401响应设置CORS头,而不是创建自己的响应?


我仍然没有解决方案。为了提供更多背景信息,请查看我的博客文章,了解我如何使用它:http://nils-blum-oeste.net/cors-api-with-oauth2-authentication-using-rails-and-angularjs - Nils Blum-Oeste
2个回答

21

我成功地使用了rack-cors gem https://github.com/cyu/rack-cors,并在我的博客中概述了我的经验。

要点:指定中间件顺序,使cors处理程序在warden之前。

config.middleware.insert_before Warden::Manager, Rack::Cors

你的方法非常有效,谢谢!然而,奇怪的是,我花了一些时间和额外的研究才意识到,我只需要更改配置中的一行代码就可以让Deviserack-cors一起工作。 - denis.peplin
嘿@digger69。你在处理其他异常方面有没有问题?比如:如果我在我的操作中抛出一个异常 def index; raise 'error'; end - Rails不会返回CORS头(rack-cors)。你能正常工作吗? - Pablo Cantero
4
你可以使用 config.middleware.insert 0, Rack::Cors 来确保 Rack::Cors 在可能的中间件之前被插入。 - Pablo Cantero

0

我们通常不喜欢CORS头。我们更喜欢使用HAProxy进行重定向。

使用HAProxy,您可以设置所有来自website.com/api/的请求被内部重定向到rails服务器。

frontend main *:80
  acl api      path_beg  -i /api
  acl app      path_beg  -i /app
backend app_backend
  reqrep    ^([^\ ]*)\ /app/(.*)  \1\ /\2
  balance   roundrobin
  server    app_files smartphoneapp.localhost:8000
backend api_backend
  reqrep    ^([^\ ]*)\ /api/(.*)  \1\ /\2
  balance   roundrobin
  server    app_api localhost:3000

CORS 可以通过使用代理来规避,但我想还必须有一种用 Devise/warden 很好地处理它的方式。 - Nils Blum-Oeste

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