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

React native axios ios not authenticating against apache/php

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

Serviceapi.js 创建并导出基础 axios 和基础 url。

const ServiceApi = axios.create({
    baseURL: BASE_URL,
    responseType: 'json'
});

AuthReducer.js 在登录时使用 post 方法手动设置授权 header。这适用于 android 和 ios 登录是 returned,我使用授权 header。

return {
    type: PERFORM_LOGIN,
    payload: {
        user: {
            name: username
        },
        request: {
            url: '/login',
            method: 'post',
            headers: { 
                'Authorization': 'Basic ' + basicAuth
            }
        }
    }

登录后,我return执行了以下redux-axios操作,您可以看到我设置了header:手动授权,效果很好。

        // 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.common.Authorization = basicAuth;
          return config;
        }, (error) => {
          Promise.reject(error);
        });

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

没问题
// Clear the auth interceptor
ServiceApi.interceptors.request.eject(authInterceptor);

同样,这在 Android 上运行良好。它看起来正在处理 ios。当我调试拦截器时,它被调用并设置 header。

但是我在 ios 上收到了 403。仔细查看请求后,请求中的androidheader和请求中的iosheader有很大区别。请求的其余部分object是相同的,只有_header object在ios和android之间不同。

Android 请求

    _headers:
        accept: "application/json, text/plain, */*"

        authorization: "Basic <correct base64 value>"

        content-type: "application/json;charset=utf-8"
__proto__: Object


IOS 请求

    _headers:
        accept: (...)

        authorization: (...)

        content-type: (...)

        get accept: ƒ ()
        
set accept: ƒ ()

        get authorization: ƒ ()
        
set authorization: ƒ ()
        
get content-type: ƒ ()

        set content-type: ƒ ()

        __proto__: Object


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

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

我再次为没有提供代码而道歉,但我会在以后有机会的时候提供。有什么我可能需要为 ios 设置额外的东西吗?或者 php for ios 需要额外的 header?

要遵循的代码。

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

编辑 2 经过进一步调查,这看起来与 apache/PHP 而不是 react-native/axios 有关。我拼凑了一个快速服务器,它模拟了 PHP 所做的相同检查: - 寻找授权 header - 打印出来 - Return 返回 403 或 200 w/ 基于那个的数据

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

编辑 3

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

1) 这是来自 IOS 模拟器 iPhone8 针对 express 服务器:

accept:"application/json, text/plain, */*"
accept-encoding:"gzip, deflate"
accept-language:"en-us"
authorization:"Basic <base 64 encoding>"
connection:"keep-alive"
content-length:"0"
host:"localhost:3000"
user-agent:"MobileApp/1 CFNetwork/978.0.7 Darwin/18.5.

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

Accept: application/json, text/plain, */*                                                             
User-Agent: MobileApp/1 CFNetwork/978.0.7 Darwin/18.5.0       
Accept-Language: en-us                                                    
Accept-Encoding: br, gzip, deflate                                        
Connection: keep-alive     

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

authorization: Basic <Base 64 encoding> 
Host: api.serviceurl.com
Connection: Keep-Alive                            
Accept-Encoding: gzip                                 
User-Agent: okhttp/3.12.1

编辑 4 因此,在玩弄和谷歌搜索了一段时间之后,事实证明问题出在 Zend Framework 和 fastcgi 上,它会自动删除授权 header。奇怪的是,它只是从 IOS 而不是 Android 这样做,这真的没有意义。

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

** 编辑 5** 到目前为止,我们已经尝试遵循要求添加以下内容的 SO 文章 (Authorization header missing in django rest_framework, is apache to blame?):

SetEnvIfNoCase Authorization ^(.*) -e=PHP_HTTP_AUTH

RewriteCond %{HTTP:Authorization} ^(.*)
RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]

结果如下:

// IOS
_SERVER[PHP_HTTP_AUTH] = <blank>
_SERVER[HTTP_AUTHORIZATION] = <blank>

// Android
_SERVER[PHP_HTTP_AUTH] = Username
_SERVER[HTTP_AUTHORIZATION] = Basic <Base65 encoded>
_SERVER[PHP_HTTP_PW] = Password

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

编辑 6

已解决(差不多)

原来这是 IOS 请求中所需的尾部斜线。我能够找到这个 link https://github.com/square/retrofit/issues/1037 问题被描述为:

For those interested: We are using Django as our backend and by default when you do not provide a trailing slash on the endpoint Django redirects from the non-slash endpoint to the slash endpoint.

现在,我们没有使用 Django,但显然对于我们的 Zend 配置来说,它是 同样的问题 - Android 能够 re-direct 没有问题,而 IOS 则没有。对该任务的另一条评论指出:

OkHttp strips the "Authorization" header when redirected across hosts (connections) via a 3xx response from the original host.

这似乎不准确,因为 Android 正在使用 OkHttp 并且工作正常。看起来 IOS 使用达尔文有问题。

编辑 我忘记了原来的 post 中的其他内容,我还不得不将我的拦截器从行 config.headers.common.Authorization = ... 更改为 config.headers.Authorization = ... ,出于某种原因保留了外壳。原来的方式将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);
    });