CakePHP2:JWT Auth 的 CORS 预检问题

Posted

技术标签:

【中文标题】CakePHP2:JWT Auth 的 CORS 预检问题【英文标题】:CakePHP2: CORS Preflight issues with JWT Auth 【发布时间】:2017-05-14 03:28:08 【问题描述】:

我正在构建一个 Ionic 1 应用程序,它与在 Cakephp 2.8 中实现的 REST API 对话,使用 JSON Web Tokens (JWT) 进行身份验证。

在未经授权的状态下,我的应用能够毫无问题地向服务器发出 GET / POST 请求。但是,一旦我通过了身份验证并且我的应用程序会随每个请求一起发送 authToken 标头,Angular 会首先自动发送 OPTIONS 预检请求。

这就是问题的开始。因为自动预检请求没有设置authToken 标头,并且因为API 端点需要授权,所以CakePHP 以302 FOUND 重定向响应/login。应用程序(或浏览器,在此测试阶段)认为这是不安全的,并且永远不会继续发出正确的请求。

我的问题:如何让 CakePHP 正确响应预检 OPTIONS 请求,以便 AngularJS 知道它可以安全地将自定义标头发送到跨域服务器?

根据this question,这就是需要发生的事情:

请求标头:

Origin: http://yourdomain.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-Custom-Header

响应标头:

Access-Control-Allow-Origin: http://yourdomain.com // Same as origin above
Access-Control-Allow-Methods: GET, POST
Access-Control-Allow-Headers: X-Custom-Header

我尝试过的事情:

-将.htaccess 设置为始终使用200 响应OPTIONS 请求。我收到 200 响应,但响应显示“您的服务器配置错误”,并且因为它没有设置正确的标头,所以真正的 $http 请求永远不会通过。

-让 CakePHP 始终以某种方式响应 OPTIONS 请求。这里的问题是让 Cake 跳过授权,跳过尝试运行控制器操作,并发送回带有正确标头设置的 HTTP 200 响应。

    // AppController::beforeFilter();
    if($this->request->is("options"))
        // Send the appropriate response based on the request
    

出于好奇,以下是在失败的$http 请求过程中交换的标头:

GENERAL:
Request URL:https://api.example.com/rest_users/profile.json
Request Method:OPTIONS
Status Code:302 Found
Remote Address:x.x.x.x:443

REQUEST HEADERS:
Accept:*/*
Accept-Encoding:gzip, deflate, sdch, br
Accept-Language:en-US
Access-Control-Request-Headers:authtoken
Access-Control-Request-Method:GET
Cache-Control:no-cache
Connection:keep-alive
DNT:1
Host:api.example.com
Origin:http://x.x.x.x:8100
Pragma:no-cache
Referer:http://x.x.x.x:8100/
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (Khtml, like Gecko) Chrome/55.0.2883.95 Safari/537.36


RESPONSE HEADERS:
Access-Control-Allow-Headers:Content-Type, x-xsrf-token
Access-Control-Allow-Methods:*
Access-Control-Allow-Origin:*
Access-Control-Max-Age:172800
Connection:Keep-Alive
Content-Encoding:gzip
Content-Length:20
Content-Type:text/html; charset=UTF-8
Date:Thu, 29 Dec 2016 18:51:30 GMT
Keep-Alive:timeout=15, max=99
Location:https://api.example.com/login
Server:Apache/2.2.15 (CentOS)
Vary:Accept-Encoding
X-Powered-By:PHP/5.3.3

【问题讨论】:

首先:您可能应该使用更常见的 Authorization 标头,而不是自定义的 authtoken 标头。第二:Access-Control-Allow-Headers:Content-Type, x-xsrf-token... 我没有看到您可以发送自定义的authtoken 标头;它不在允许的列表中。这可能就是问题所在。 我仍然需要在响应中设置 Access-Control-Allow-Origin: x.x.x.x(通常是 IP 地址)标头。它不能是通配符。需要自定义标头,因为请求将从应用程序发送。 Access-Control-Allow-Origin 通常不是 IP 地址,通常是域名...除非您通过 IP(在 URL 栏中)访问您的站点,否则它将是完全限定的域名。 * 可以很好地用于测试,您可能希望稍后将其锁定。但这既不是这里也不是那里......不知道你为什么提出它......我在谈论 Access-Control-Allow-Headers 目前不允许你发送authtoken header并将阻止您的请求,因为您的配置不允许。 【参考方案1】:

我找到了一个允许 CakePHP 正确处理 CORS 预检的解决方案。它设置标题,发送响应,并在请求的操作可以运行之前关闭 Cake。

确保在所有控制器中都有parent::beforeFilter();,以便此代码运行。

在 AppController::beforeFilter():

    if($this->request->is("options"))
        // Set the headers
        $this->response->header('Access-Control-Allow-Origin','*');
        $this->response->header('Access-Control-Allow-Methods','*');
        $this->response->header('Access-Control-Allow-Headers','Content-Type, Authorization');
        // Send the response
        $this->response->send();
        // Don't do anything else!
        $this->_stop();
    

【讨论】:

你可能想看看dispatcher filtersCakeResponse::cors()

以上是关于CakePHP2:JWT Auth 的 CORS 预检问题的主要内容,如果未能解决你的问题,请参考以下文章

在我的 Spring Boot 应用程序中实现 jwt auth 后,Ive cors 问题再次出现

应用 jwt auth 包装器时,Flask-cors 包装器不起作用。

在安装 tymon/jwt-auth 后的 laravel Backend REST API 应用程序中再次遇到 CORS 错误

在 Angular 中使用 MSAL 和在 WebAPI 中使用 JWT Auth 时 API 请求触发 CORS 错误

使用spring security的auth api调用的cors错误

Laravel + Dingo + JWT + cors 和 OPTIONS 方法