React 本机 axios ios 未针对 apache/php 进行身份验证

ken*_*son 4 php apache zend-framework react-native axios

我是在回家的路上发布的,所以请原谅缺少代码,但我会尽力尽可能详细,并在今晚尽可能添加代码。所以本质上我有一个使用 redux 和 axios 的 React Native 应用程序。简短的回顾(遵循的代码)可能会解释我做错了什么。

\n\n

服务api.js \n使用基本 url 创建并导出基本 axios。

\n\n
const ServiceApi = axios.create({\n    baseURL: BASE_URL,\n    responseType: \'json\'\n});\n
Run Code Online (Sandbox Code Playgroud)\n\n

AuthReducer.js \n登录时使用 post 方法手动设置授权标头。这适用于 android 和 ios 登录返回,我使用授权标头。

\n\n
return {\n    type: PERFORM_LOGIN,\n    payload: {\n        user: {\n            name: username\n        },\n        request: {\n            url: \'/login\',\n            method: \'post\',\n            headers: { \n                \'Authorization\': \'Basic \' + basicAuth\n            }\n        }\n    }\n
Run Code Online (Sandbox Code Playgroud)\n\n

登录时,我返回以下 redux-axios 操作,您可以看到我设置了标题:手动授权,这效果很好。

\n\n
        // On login success, set the authInterceptor responsible for adding headers\n        authInterceptor = ServiceApi.interceptors.request.use((config) => {\n          console.log(`Attaching Authorization to header ${basicAuth}`);\n          config.headers.common.Authorization = basicAuth;\n          return config;\n        }, (error) => {\n          Promise.reject(error);\n        });\n
Run Code Online (Sandbox Code Playgroud)\n\n

注销时我清除拦截器。我选择在登录和注销时添加和删除,而不是仅仅因为它总是在那里。这可能是个问题,但对于 Android 来说没问题

\n\n
// Clear the auth interceptor\nServiceApi.interceptors.request.eject(authInterceptor);\n
Run Code Online (Sandbox Code Playgroud)\n\n

同样,这一切在 Android 上都运行良好。而且它似乎可以在 ios 上运行。当我调试拦截器时,它会被调用并设置标头。

\n\n

但我在 ios 上得到了 403。更详细地查看请求后,请求中的android标头和请求中的ios标头有很大的区别。ios 和 android 之间请求对象的其余部分是相同的,只有 _header 对象不同。

\n\n

安卓请求

\n\n
    _headers:\n        accept:\xc2\xa0"application/json, text/plain, */*"\xe2\x80\xa8\n        authorization:\xc2\xa0"Basic <correct base64 value>"\xe2\x80\xa8\n        content-type:\xc2\xa0"application/json;charset=utf-8"\xe2\x80\xa8__proto__:\xc2\xa0Object\xe2\x80\xa8\n
Run Code Online (Sandbox Code Playgroud)\n\n

IOS请求

\n\n
    _headers:\n        accept:\xc2\xa0(...)\xe2\x80\xa8\n        authorization:\xc2\xa0(...)\xe2\x80\xa8\n        content-type:\xc2\xa0(...)\xe2\x80\xa8\n        get accept:\xc2\xa0\xc6\x92\xc2\xa0()\n        \xe2\x80\xa8set accept:\xc2\xa0\xc6\x92\xc2\xa0()\xe2\x80\xa8\n        get authorization:\xc2\xa0\xc6\x92\xc2\xa0()\n        \xe2\x80\xa8set authorization:\xc2\xa0\xc6\x92\xc2\xa0()\n        \xe2\x80\xa8get content-type:\xc2\xa0\xc6\x92\xc2\xa0()\xe2\x80\xa8\n        set content-type:\xc2\xa0\xc6\x92\xc2\xa0()\xe2\x80\xa8\n        __proto__:\xc2\xa0Object\xe2\x80\xa8\n
Run Code Online (Sandbox Code Playgroud)\n\n

由于存在差异,设置断点查看控制台,error.request._headers.authorization;我会得到与 Android 标头包含的相同的“Basic:”内容。

\n\n

index.php \n后端服务是一个 php 文件,它执行 $_SERVER[\'PHP_AUTH_USER\'] 操作,如果未设置,则会失败 403,这就是正在发生的情况。我无权访问 php,我只是被告知这就是它正在使用的内容。

\n\n

我再次为没有提供代码而道歉,但稍后有机会时我会提供。ios 有什么需要我额外设置的吗?或者也许 ios 的 php 需要额外的标头?

\n\n

要遵循的代码。

\n\n

编辑用代码更新,希望我没有留下任何编码的登录信息。

\n\n

编辑2经过进一步调查,这看起来与 apache/PHP 有关,而不是与 React-native/axios 有关。我组装了一个 Express 服务器,它模拟了 PHP 所做的相同检查:\n- 查找授权标头\n- 打印它\n- 返回 403 或 200 以及基于此的数据

\n\n

当在模拟器上使用完全相同的应用程序指向http://localhost:3000运行时,我得到了我所期望的结果。除此之外,当我在模拟器上时,我实际上无法登录实时 URL(即使我可以在常规设备上登录),我会收到相同的 403 错误,但这次要早一点。

\n\n

编辑3

\n\n

为了从服务器提供更多信息,以下是我能够记录的三个请求:

\n\n

1) 这是来自 iOS 模拟器 iPhone8 针对 Express 服务器的:

\n\n
accept:"application/json, text/plain, */*"\naccept-encoding:"gzip, deflate"\naccept-language:"en-us"\nauthorization:"Basic <base 64 encoding>"\nconnection:"keep-alive"\ncontent-length:"0"\nhost:"localhost:3000"\nuser-agent:"MobileApp/1 CFNetwork/978.0.7 Darwin/18.5.\n
Run Code Online (Sandbox Code Playgroud)\n\n

2) 这是从同一个模拟器到apache/PHP (5.3.3),我们可以看到没有授权标头。

\n\n
Accept: application/json, text/plain, */*                                                             \nUser-Agent: MobileApp/1 CFNetwork/978.0.7 Darwin/18.5.0       \nAccept-Language: en-us                                                    \nAccept-Encoding: br, gzip, deflate                                        \nConnection: keep-alive     \n
Run Code Online (Sandbox Code Playgroud)\n\n

3) 这是从 Android 到 apache/PHP (5.3.3) 的:

\n\n
authorization: Basic <Base 64 encoding> \nHost: api.serviceurl.com\nConnection: Keep-Alive                            \nAccept-Encoding: gzip                                 \nUser-Agent: okhttp/3.12.1\n
Run Code Online (Sandbox Code Playgroud)\n\n

编辑 4 \n因此,经过一段时间的尝试和谷歌搜索后,发现问题出在 Zend Framework 和 fastcgi 上,它们会自动删除授权标头。奇怪的是,它只在 IOS 上执行,而不是在 Android 上执行,这确实没有意义。

\n\n

我们在日志中注意到的一件事是,它接受 Android 和 Postman 作为 POST,但它将 IOS 请求记录为 GET。我不完全确定这是怎么回事,但这似乎是另一个区别。我已经更新了任务以将 zend 作为标签。在 apache/zend 上有很多关于使用 ReWriteMod 解决此问题的文章,因此我将首先尝试一下,看看它是否可以解决问题。

\n\n

** 编辑 5** \n到目前为止,我们已经尝试遵循 SO 文章,这些文章要求添加以下内容(django Rest_framework 中缺少授权标头,是 apache 的错吗?):

\n\n
SetEnvIfNoCase Authorization ^(.*) -e=PHP_HTTP_AUTH\n\nRewriteCond %{HTTP:Authorization} ^(.*)\nRewriteRule .* - [e=HTTP_AUTHORIZATION:%1]\n
Run Code Online (Sandbox Code Playgroud)\n\n

结果如下:

\n\n
// IOS\n_SERVER[PHP_HTTP_AUTH] = <blank>\n_SERVER[HTTP_AUTHORIZATION] = <blank>\n\n// Android\n_SERVER[PHP_HTTP_AUTH] = Username\n_SERVER[HTTP_AUTHORIZATION] = Basic <Base65 encoded>\n_SERVER[PHP_HTTP_PW] = Password\n
Run Code Online (Sandbox Code Playgroud)\n\n

所以我们知道 Header Authorization 正在进入 Apache,但现在它是空白的。我正在研究一些其他的答案,但搜索仍在继续......

\n\n

编辑6

\n\n

已解决(左右)

\n

ken*_*son 5

结果发现这是 IOS 请求中需要的尾部斜杠。我找到了此链接https://github.com/square/retrofit/issues/1037,其中问题描述为:

对于那些感兴趣的人:我们使用 Django 作为后端,默认情况下,当您不在端点上提供尾部斜杠时,Django 会从非斜杠端点重定向到斜杠端点。

现在,我们没有使用 Django,但显然对于我们的 Zend 配置来说,这是同样的问题 - Android 能够毫无问题地重定向,而 IOS 则不能。关于该任务的另一条评论指出:

当通过来自原始主机的 3xx 响应跨主机(连接)重定向时,OkHttp 会去除“授权”标头。

这似乎不准确,因为 Android 使用 OkHttp 并且工作正常。看起来使用 Darwin 的 IOS 有这个问题。

编辑 我忘记了原来帖子中的其他内容,我还必须将拦截器从由于某种原因保留外壳的线路更改config.headers.common.Authorization = ...为。config.headers.Authorization = ...原来的方式将Authorization转换为授权,而后者保留为Authorization。不确定这是否是一个问题,但无论如何我做到了。

// On login success, set the authInterceptor responsible for adding headers
authInterceptor = ServiceApi.interceptors.request.use((config) => {
      console.log(`Attaching Authorization to header ${basicAuth}`);
      config.headers.Authorization = basicAuth;
      return config;
    }, (error) => {
      Promise.reject(error);
    });
Run Code Online (Sandbox Code Playgroud)