已完成 401 未授权请求被重定向到不允许需要预检的跨域请求

Posted

技术标签:

【中文标题】已完成 401 未授权请求被重定向到不允许需要预检的跨域请求【英文标题】:Completed 401 unauthorized The request was redirected to which is disallowed for cross-origin requests that require preflight 【发布时间】:2016-10-19 07:18:42 【问题描述】:

这个问题听起来像是重复的,但我已经尝试了 *** 上其他类似问题中的所有步骤,但没有一个有效。我正在尝试使用 ionic 连接到 Rails API。

我的设置是 Rails 4,用于身份验证的设计,用于基于令牌的 API 请求的 simple_token_authentication gem 和用于移动应用的 ionic。

我可以通过将带有正确用户名和密码的登录请求传递给设计会话控制器 api 来从 ionic 登录,并在通过设计 api 成功登录后获取令牌。

之后,当我尝试使用访问令牌通过 get 查询访问任何控制器的索引时: http://localhost:3002/api/categories?token=1098ccee839952491a4 或 http://localhost:3002/api/employers?token=1098ccee839952491a4

响应是设计的登录页面。在 rails 日志中,它显示

Started GET "/api/categories?token=1098ccee839952491a43" for ::1 at 2016-06-17 17:45:55 +0530
Processing by Api::CategoriesController#index as html
  Parameters: "token"=>"1098ccee839952491a43"
  User Load (0.7ms)  SELECT `users`.* FROM `users` WHERE `users`.`authentication_token` = '1098ccee839952491a43'
Completed 401 Unauthorized in 3ms (ActiveRecord: 0.7ms)


Started GET "/users/sign_in" for ::1 at 2016-06-17 17:45:55 +0530
Processing by Devise::SessionsController#new as HTML
  Rendered devise/shared/_links.html.erb (6.5ms)
  Rendered devise/sessions/new.html.erb within layouts/login (78.3ms)
Completed 200 OK in 3850ms (Views: 3847.1ms | ActiveRecord: 0.0ms)

我确定令牌是正确的,因为我已经交叉检查了数据库中的令牌。此外,我还包含 rack-cors gem 及其配置为允许跨域请求的任何来源。

在我的 application.rb 中,cors 条目如下所示

class Application < Rails::Application
    config.active_record.raise_in_transactional_callbacks = true

    config.middleware.insert_before 0, "Rack::Cors" do
      allow do
        origins '*'
        resource '*', :headers => :any, :methods => [:get, :post, :options]
      end
    end

  end

ionic 中 controllers.js 中的 GET 请求如下所示:-

 $http(
        method: 'GET',
        headers: 
         
            'X-XSRF-TOKEN': window.localStorage.getItem("token") ,
         ,
        url: config.apiUrl+"/categories?token="+window.localStorage.getItem("token") ,
            ).then(function successCallback(response) 
                                console.log(response);

              , function errorCallback(response) 
                $ionicPopup.alert(
                    title: 'Alert',
                    template: response.data.message,
                );
              );   

请求发起后,Chrome 开发者控制台显示如下信息

XMLHttpRequest 无法加载 http://localhost:3002/api/categories?token=1098ccee839952491a43。这 请求被重定向到“http://localhost:3002/users/sign_in”,其中 对于需要预检的跨域请求是不允许的。

我从服务器得到的响应头是

常规

Request URL:http://localhost:3002/api/categories?token=1098ccee839952491a43
Request Method:GET
Status Code:302 Found
Remote Address:[::1]:3002

响应标头

view source
Access-Control-Allow-Credentials:true
Access-Control-Allow-Methods:GET, POST, OPTIONS
Access-Control-Allow-Origin:http://localhost:8100
Access-Control-Expose-Headers:
Access-Control-Max-Age:1728000
Cache-Control:no-cache
Connection:Keep-Alive
Content-Length:101
Content-Type:text/html; charset=utf-8
Date:Fri, 17 Jun 2016 12:26:13 GMT
Location:http://localhost:3002/users/sign_in
Server:WEBrick/1.3.1 (Ruby/2.2.1/2015-02-26)
Set-Cookie:_backend_session=c05LRTgzdXNVdGNFeHcwaDNtRDkxZ1RBbXFNaDFNbE1zMTV6OGhFZG1VODdON2k4ODN0ZTg3YXo5OU5hOTZkcUNmR3VTaGVRQzBOUElCNnMrODhnemVCbUhQbUs2azNHdmVnbFpoL2JiRDA5S1I4NCtsVWNhOEpqeDdoYWxXR3hHNDg5RzNRcUlpcDZ4QWswY2NmUlpYbUkvTnpaVEViNXh6ZExCZkNyTXA0allMcW1RVGg1MjRLVnpEbzlSSVk4dGRUSTNsTUZFNEFOcVJxdm1hWXNaSFEzdnlSN01DZ2FTdEJYUTdUUGxucU44cFBMbDZ6RXlhVUx2ZHArWlNCVWgyTWs2emRrSXNGbTQ3ZVVQL0NCR0E9PS0tbmFzajFXZnZnd25oUkRFRjhxSy81QT09--281b2bd6413653ca006abc80f13329d6bf3ad0f5; path=/; HttpOnly
Vary:Origin
X-Content-Type-Options:nosniff
X-Frame-Options:SAMEORIGIN
X-Request-Id:3097ec28-6d55-4c70-90c9-de221b4321e3
X-Runtime:0.021444
X-Xss-Protection:1; mode=block

请求标头

view source
Accept:application/json, text/plain, */*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:en-US,en;q=0.8
Connection:keep-alive
Host:localhost:3002
Origin:http://localhost:8100
Referer:http://localhost:8100/
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.84 Safari/537.36
X-XSRF-TOKEN:1098ccee839952491a43

【问题讨论】:

你能否将设置的请求标头:“Access-Control-Allow-Origin:localhost:8100”替换为“Access-Control-Allow-Origin: *”然后再试一次 为什么同时使用 X-XSRF-TOKEN 标头和令牌作为查询参数?显然这不是 CORS 问题,您的控制器中存在身份验证问题。如果是 CORS 问题,您根本看不到 GET 请求。你能在Api::CategoriesController分享你的代码吗? 查看***.com/questions/34949492/… 的答案,了解如何解决此问题的详细信息。此外,正如那里所指出的,这种对重定向的限制不再在规范中,但浏览器需要更新其实现以匹配规范更改。 【参考方案1】:

我认为与Access-Control-Allow-Credentials:true 标头有关的问题,试试这个:

$http(
        method: 'GET',
        withCredentials: true,
        headers: 
         
            'X-XSRF-TOKEN': window.localStorage.getItem("token") ,
         ,
        url: config.apiUrl+"/categories?token="+window.localStorage.getItem("token") ,
            ).then(function successCallback(response) 
                                console.log(response);

              , function errorCallback(response) 
                $ionicPopup.alert(
                    title: 'Alert',
                    template: response.data.message,
                );
              );   

它也会将 cookie 发送到 api 服务器

【讨论】:

很棒的收获!更仔细地阅读响应标头是了解如何解决此问题的关键。【参考方案2】:

试试这个

app.config(function($sceDelegateProvider) 
 $sceDelegateProvider.resourceUrlWhitelist([
    // Allow same origin resource loads.
    'self',
    // Allow loading from our assets domain.  Notice the difference between * and **.
    'http://localhost:3002/**'
  ]);

);

浏览器会自动从您需要允许域的陌生人 url 中阻止资源。

【讨论】:

以上是关于已完成 401 未授权请求被重定向到不允许需要预检的跨域请求的主要内容,如果未能解决你的问题,请参考以下文章

Google OAuth2:重定向已被 CORS 政策阻止:请求需要预检,不允许遵循跨域重定向

CORS:对预检请求的响应未通过访问控制检查:预检请求不允许重定向

http status code

ASP.NET Core Web API + Angular 对预检请求的响应未通过访问控制检查:预检请求不允许重定向

401 未经授权响应 CORS 预检选项请求

如何解决“预检无效(重定向)”或“预检请求不允许重定向”