反应本机 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);
});
我在回家的路上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);
});