来自https服务器的具有自签名证书的React-native fetch()

Bor*_* WM 25 react-native

我正在尝试与具有自签名证书的https服务器通信.

我可以从.NET应用程序(使用ServicePointManager.ServerCertificateValidationCallback事件)做到这一点,从(使用allowsAnyHTTPSCertificateForHost)或Web浏览器(只需要声明的是,证书是可信的)原生的iOS应用程序.

但我不能让它在react-native应用程序中工作(在Android和iOS模拟器中都没有).

我尝试了不同的东西,但仍未成功.

我知道那里有一些类似的主题:
使用ReactNative App中的fetch API忽略自签名SSL证书的错误?
如果SSL(HTTPS)证书是反应原住民的XMLHttpRequest请求失败不是有效的
抓取在本地的反应不会工作在Android上使用SSL
从一个基于SSL服务器获取数据的问题
无法使用API调用反应本机进行

但是它们要么不包含答案要么不起作用(而且它们根本不包括android编程).搜索其他资源也没有效果.

我相信应该有一个简单的方法来使用自签名证书.我错了吗?有人知道吗(iOS和Android都有)?

San*_*son 33

免责声明:此解决方案应该是临时的并记录在案,以便它不会停留在软件的生产阶段,这仅用于开发.

对于iOS,您只需打开您的xcodeproject(在RN中的iOS文件夹中),打开后,转到RCTNetwork.xcodeproj,在该项目中,导航到RCTHTTPRequestHandler.m

在该文件中,您将看到如下所示的行:

#pragma mark - NSURLSession delegate
Run Code Online (Sandbox Code Playgroud)

在该行之后,添加此功能

- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
{
  completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]);
}
Run Code Online (Sandbox Code Playgroud)

瞧,您现在可以在没有有效证书的情况下对API进行不安全的调用.

这应该足够了,但是如果你仍然遇到问题,你可能需要转到项目的info.plist,左键单击它并选择打开为...源代码.

最后加入

<key>NSAppTransportSecurity</key>
  <dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
  </dict>
  <key>NSExceptionDomains</key>
    <dict>
        <key>localhost</key>
        <dict>
            <key>NSExceptionAllowsInsecureHTTPLoads</key>
            <true/>
        </dict>
        <key>subdomain.example.com</key>
        <dict>
            <key>NSIncludesSubdomains</key>
            <true/>
            <key>NSExceptionAllowsInsecureHTTPLoads</key>
            <true/>
        </dict>
    </dict>
Run Code Online (Sandbox Code Playgroud)

所以你的文件看起来像这样

    ...
    <key>UISupportedInterfaceOrientations</key>
    <array>
        <string>UIInterfaceOrientationPortrait</string>
        <string>UIInterfaceOrientationLandscapeLeft</string>
        <string>UIInterfaceOrientationLandscapeRight</string>
    </array>
    <key>UIViewControllerBasedStatusBarAppearance</key>
    <false/>
    <key>NSLocationWhenInUseUsageDescription</key>
    <string></string>
  <key>NSAppTransportSecurity</key>
  <dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
  </dict>
  <key>NSExceptionDomains</key>
    <dict>
        <key>localhost</key>
        <dict>
            <key>NSExceptionAllowsInsecureHTTPLoads</key>
            <true/>
        </dict>
        <key>subdomain.example.com</key>
        <dict>
            <key>NSIncludesSubdomains</key>
            <true/>
            <key>NSExceptionAllowsInsecureHTTPLoads</key>
            <true/>
        </dict>
    </dict>
</dict>
</plist>
Run Code Online (Sandbox Code Playgroud)

对于真正的生产就绪解决方案,/sf/answers/2545785231/该解决方案更好

  • @SantiagoJimenezWilson:你有2017年的Android答案吗?谢谢. (6认同)
  • 我会在一周左右的时间内为Android添加答案,如果您现在需要,请告诉我,也许我可以告诉您到目前为止我在Android中所做的事情 (2认同)

use*_*ser 14

我在android中也遇到了同样的问题。最后我找到了这个问题的解决方案。

import com.facebook.react.modules.network.OkHttpClientFactory;
import com.facebook.react.modules.network.OkHttpClientFactory;
import com.facebook.react.modules.network.OkHttpClientProvider;
import com.facebook.react.modules.network.ReactCookieJarContainer;

import java.security.cert.CertificateException;
import java.util.ArrayList;

import java.util.List;

import java.util.concurrent.TimeUnit;


import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import okhttp3.CipherSuite;
import okhttp3.ConnectionSpec;
import okhttp3.OkHttpClient;
import okhttp3.TlsVersion;

import static android.content.ContentValues.TAG;

public class CustomClientFactory implements OkHttpClientFactory {
    private static final String TAG = "OkHttpClientFactory";
    @Override
    public OkHttpClient createNewNetworkModuleClient() {
        try {
            // Create a trust manager that does not validate certificate chains
            final TrustManager[] trustAllCerts = new TrustManager[]{
                    new X509TrustManager() {
                        @Override
                        public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
                        }

                        @Override
                        public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
                        }

                        @Override
                        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                            return new java.security.cert.X509Certificate[]{};
                        }
                    }
            };

            // Install the all-trusting trust manager
            final SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
            // Create an ssl socket factory with our all-trusting manager
            final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();



            OkHttpClient.Builder builder = new OkHttpClient.Builder()
                    .connectTimeout(0, TimeUnit.MILLISECONDS).readTimeout(0, TimeUnit.MILLISECONDS)
                    .writeTimeout(0, TimeUnit.MILLISECONDS).cookieJar(new ReactCookieJarContainer());
            builder.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0]);
            builder.hostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });

            OkHttpClient okHttpClient = builder.build();
            return okHttpClient;
        } catch (Exception e) {
            Log.e(TAG, e.getMessage());
            throw new RuntimeException(e);
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

在我们的 Android 应用程序 MainApplication.java 中

 @Override
  public void onCreate() {
    super.onCreate();
    SoLoader.init(this, /* native exopackage */ false);  
    OkHttpClientProvider.setOkHttpClientFactory(new CustomClientFactory()); //add this line.
  }  
Run Code Online (Sandbox Code Playgroud)

它为我工作。可能对所有人都有帮助。

  • 你能解释一下吗?您正在使用什么名称创建一个新文件?MainApplication.java 中是否有任何导入? (2认同)
  • 还要在 MainApplication 中添加“import com.facebook.react.modules.network.OkHttpClientProvider;” (2认同)

小智 5

这是由于用于加密的自签名证书而发生的。由于 android 中的安全原因,它需要 CA 授权签名或受信任的证书

使用这个插件来避免这种情况。

https://www.npmjs.com/package/react-native-fetch-blob

RNFetchBlob.config({
  trusty : true
})
.then('GET', 'https://xxxxx.com')
.then((resp) => {
  // ...
})
Run Code Online (Sandbox Code Playgroud)

添加 config trusty as true以在 POST 或 GET API 时信任证书


Ali*_*gji 5

我通过执行以下操作在 Android 上工作:

  1. 在“设置”->“安全和位置”>“高级”>“加密和凭据”>“从存储安装”下的设备上安装 CA。您可以通过设备上的网络浏览器访问域来确认它已正确安装。如果证书有效,则安装 CA。
  2. res/xml/network_security_config.xml使用以下内容创建网络安全配置。更新域。
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config cleartextTrafficPermitted="true">
        <!-- For React Native Hot-reloading system -->
        <!-- If you are running on a device insert your computer IP -->
        <domain includeSubdomains="true">localhost</domain>
        <domain includeSubdomains="true">your self signed domain</domain>

        <trust-anchors>
            <certificates src="system" />
            <certificates src="user" />
        </trust-anchors>
    </domain-config>

    <base-config cleartextTrafficPermitted="false" />
</network-security-config>
Run Code Online (Sandbox Code Playgroud)
  1. 从您的AndroidManifest.xml.
<?xml version="1.0" encoding="utf-8"?>
<manifest ... >
    <application android:networkSecurityConfig="@xml/network_security_config"
                    ... >
        ...
    </application>
</manifest>
Run Code Online (Sandbox Code Playgroud)


归档时间:

查看次数:

32192 次

最近记录:

6 年,1 月 前