React native 使用自签名证书从https服务器响应本机获取()

React native 使用自签名证书从https服务器响应本机获取(),react-native,React Native,我正在尝试与具有自签名证书的https服务器通信 我可以从.NET应用程序(使用ServicePointManager.ServerCertificateValidationCallback事件)、本机iOs应用程序(使用allowsAnyHTTPSCertificateForHost)或web浏览器(只需声明证书受信任)执行此操作 但我无法让它在react本机应用程序中工作(无论是在Android还是在iOS模拟器中) 我尝试过不同的事情,但仍然没有成功 我知道那里有一些类似的话题:

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

我可以从.NET应用程序(使用ServicePointManager.ServerCertificateValidationCallback事件)、本机iOs应用程序(使用allowsAnyHTTPSCertificateForHost)或web浏览器(只需声明证书受信任)执行此操作

但我无法让它在react本机应用程序中工作(无论是在Android还是在iOS模拟器中)

我尝试过不同的事情,但仍然没有成功

我知道那里有一些类似的话题:




但它们要么不包含答案,要么不起作用(而且它们根本不涉及android编程)。搜索其他资源也没有什么成效


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

免责声明:此解决方案应该是临时的,并且有文档记录,这样它就不会停留在软件的生产阶段,这只是为了开发

对于iOS,您所要做的就是打开您的xcodeproject(在RN中的iOS文件夹中),打开后,转到RCTNetwork.xcodeproj,并在该项目中导航到RCTHTTPRequestHandler.m

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

#pragma标记-NSURLSession委托
在该行之后添加此函数

-(void)URLSession:(NSURLSession*)session direceivechallenge:(nsurauthenticationchallenge*)challengecompletionhandler:(void(^)(NSURLSessionAuthChallengeDisposition disposition,NSURLCredential*credential))completionHandler
{
completionHandler(NSURLSessionAuthChallengeUseCredential,[nsurlCredentialCredential credentialForTrust:challenge.protectionSpace.serverTrust]);
}
瞧,您现在可以在没有有效证书的情况下对API进行不安全的调用

这应该足够了,但如果您仍然有问题,您可能需要转到项目的info.plist,左键单击它并选择open as。。。源代码

最后再加上

NSAppTransportSecurity
NSAllowsArbitraryLoads
NSExceptionDomains
本地服务器
N异常低安全Http负载
subdomain.example.com
n包括多个域
N异常低安全Http负载
所以你的文件看起来像这样

。。。
UI支持接口方向

这个解决方案更好

借鉴@Santiago Jimenez Wilson的答案

显然,修补react native本身是非常肮脏的,所以我们采用了建议的覆盖并将其提取到一个类别中

只需在项目中的某个地方创建一个名为
RCTHTTPRequestHandler+yourPatchName.m
的新文件:

//
//  RCTHTTPRequestHandler+yourPatchName
//

#import "RCTBridgeModule.h"
#import "RCTHTTPRequestHandler.h"

@implementation RCTHTTPRequestHandler(yourPatchName)

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

下一步是在dev和prod之间进行区分,只重载dev的方法。

这是由于用于加密的自签名证书造成的。由于安卓系统中的安全原因,它需要授权机构签名或受信任的证书

使用此插件可以避免这种情况


将configtrusty添加为true以在发布或获取API时信任证书

我通过以下操作在Android上实现了这一点:

  • 在设备上的“设置”->“安全性和位置”->“高级”->“加密和凭据”->“从存储安装”下安装CA。您可以通过设备上的web浏览器访问域来确认已正确安装。如果证书验证,则安装CA
  • 使用以下内容在
    res/xml/network\u security\u config.xml
    创建网络安全配置。更新域

  • 只是为寻找Android解决方案的用户添加信息。 默认情况下,作为react native不处理SSL错误。对于必须通过“https”而不是“http”连接的网站,有一种简单的方法来运行WebView

    我假设您已经使用NPM安装了react native webview模块。如果没有,请使用google

    一旦在“node_modules”文件夹中有了“react native webview”模块。 进去 “\node\u modules>>react native webview>>android>>src>>main>>java>>com>>react nativecommunity>>webview”

    在文本编辑器中打开“RNCWebViewManager.java”文件并添加以下代码

    在导入部分添加这两个依赖项

    ....
    import android.webkit.SslErrorHandler;
    import android.net.http.SslError;
    ....
    
    现在在同一个文件中搜索下面的“类” 受保护的静态类RNCWebViewClient扩展了WebViewClient

    并添加此方法

    @Override
    public void onReceivedSslError(WebView webView, SslErrorHandler handler, SslError 
    error) {
        if (error.toString() == "piglet")
            handler.cancel();
        else
            handler.proceed(); // Ignore SSL certificate errors
    }
    
    接下来保存文件并构建项目。它现在不会显示空白页并处理无效的SSL错误

    注:

  • 仅当您使用“react native WebView”中的“WebView”而不是“react native”中不推荐使用的“WebView”时,此解决方案才有效
  • 确保您已经将“react native”与“react native webview”链接,否则它将不会包含在您的android项目中
  • “RNCWebViewModule”、“RNCWebViewManager”、“RNCWebViewFileProvider”类中可能存在版本错误(在使用导入打开android项目后,使用
    react native run android
    在AndroidStudio内部正确构建项目后,将可见),您可以使用AndroidStudio轻松修复该错误

  • 我在安卓系统中也面临同样的问题。最后我找到了解决这个问题的办法

    import com.facebook.react.modules.network.OkHttpClientFactory;
    导入com.facebook.react.modules.network.OkHttpClientFactory;
    导入com.facebook.react.modules.network.OkHttpClientProvider;
    导入com.facebook.react.modules.network.ReactCookieJarContainer;
    导入java.security.cert.CertificateException;
    导入java.util.ArrayList;
    导入java.util.List;
    导入java.util.concurrent.TimeUnit;
    导入javax.net。
    
    <?xml version="1.0" encoding="utf-8"?>
    <manifest ... >
        <application android:networkSecurityConfig="@xml/network_security_config"
                        ... >
            ...
        </application>
    </manifest>
    
    ....
    import android.webkit.SslErrorHandler;
    import android.net.http.SslError;
    ....
    
    @Override
    public void onReceivedSslError(WebView webView, SslErrorHandler handler, SslError 
    error) {
        if (error.toString() == "piglet")
            handler.cancel();
        else
            handler.proceed(); // Ignore SSL certificate errors
    }
    
     * run this script normally for patching,
     * pass -r argument at the end of the command for removing the patch
     * ex: 
     * patching:         $ node patch_ssl_bypass.js
     * removing patch:   $ node patch_ssl_bypass.js -r
     */
    
    var fs = require('fs');
    
    const isRemove = process.argv[process.argv.length-1] == '-r';
    
    const file =
      'node_modules/react-native/Libraries/Network/RCTHTTPRequestHandler.mm';
    const delemeter = '#pragma mark - NSURLSession delegate';
    const code = `
    - (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
    {
      completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]);
    }
    `;
    console.log('#############   Reading File   ###############');
    fs.readFile(file, 'utf8', function(error, data) {
      if (error) {
        console.log('#############  error reading file  ###############');
        console.error(error);
        return;
      }
      if (data.indexOf(code) < 0 && !isRemove) {
        console.log('#############  Patch is not done.  ###############');
        console.log('#############  Patching file  ###############');
        var parts = data.split(delemeter);
        var newCodeBlock = parts[0] + delemeter + '\n' + code + '\n'+parts[1];
        fs.writeFile(file,newCodeBlock,function(){
            console.log('#############  Successfully patched file  ###############');
            console.log('#############  re build the ios project  ###############');
        })
      }else{
          if (isRemove){
              var updatedCode = data.replace(code,'');
            fs.writeFile(file,updatedCode,function(){
                console.log('#############  Successfully removed patch  ###############');
                console.log('#############  re build the ios project  ###############');
            })
          }else{
            console.log('#############  File already patched. No need again  ###############');
          }
      }
    });