解决 Android 上的 .NET MAUI/Xamarin.AndroidX 应用调用 ASP.NET Core API 端点时 SSL 连接被拒绝的问题

从虚拟机调用本地API报各种 SSL 连接不上的错误,这给本地调试造成了极大的不便,在被这个问题困扰了多日以后,终于在GitHub上找到答案

基于这个 帖子 ,有一个回复

他写了一个帮助类,专门用来调试本地的API,并给出了这个调用类的用法,此帮助类如下

using System.Net.Security;

public class DevHttpsConnectionHelper
{
    public DevHttpsConnectionHelper(int sslPort)
    {
        SslPort = sslPort;
        DevServerRootUrl = FormattableString.Invariant($"https://{DevServerName}:{SslPort}");
        LazyHttpClient = new Lazy<HttpClient>(() => new HttpClient(GetPlatformMessageHandler()));
    }

    public int SslPort { get; }

    public string DevServerName =>
#if WINDOWS
        "localhost";
#elif ANDROID
        "10.0.2.2";
#else
        throw new PlatformNotSupportedException("Only Windows and Android currently supported.");
#endif

    public string DevServerRootUrl { get; }

    private Lazy<HttpClient> LazyHttpClient;
    public HttpClient HttpClient => LazyHttpClient.Value;

    public HttpMessageHandler? GetPlatformMessageHandler()
    {
#if WINDOWS
        return null;
#elif ANDROID
        var handler = new CustomAndroidMessageHandler();
        handler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) =>
        {
            if (cert != null && cert.Issuer.Equals("CN=localhost"))
                return true;
            return errors == SslPolicyErrors.None;
        };
        return handler;

#else
        throw new PlatformNotSupportedException("Only Windows and Android currently supported.");
#endif
    }

#if ANDROID
    internal sealed class CustomAndroidMessageHandler : Xamarin.Android.Net.AndroidMessageHandler
    {
        protected override Javax.Net.Ssl.IHostnameVerifier GetSSLHostnameVerifier(Javax.Net.Ssl.HttpsURLConnection connection)
            => new CustomHostnameVerifier();

        private sealed class CustomHostnameVerifier : Java.Lang.Object, Javax.Net.Ssl.IHostnameVerifier
        {
            public bool Verify(string? hostname, Javax.Net.Ssl.ISSLSession? session)
            {
                return
                    Javax.Net.Ssl.HttpsURLConnection.DefaultHostnameVerifier.Verify(hostname, session)
                    || hostname == "10.0.2.2" && session.PeerPrincipal?.Name == "CN=localhost";
            }
        }
    }
#endif
}

 在安卓机里面是没有 localhost 的,也没有 127.0.0.1 代表本机的取而代之的是 10.0.2.2 。在 HTTPS 里面,证书是被强制使用的,本地 Web API 会有一个默认证书,他里面带一个 “CN=localhost” 所以上面的类针对这个进行了过滤,并且 Android 的底层用的不是默认的 .net 的 HttpClient ,使用了 GetPlatformMessageHandler 进行了重写,这个可是Java 的包。

我的本地调用使用

                            var devSslHelper = new DevHttpsConnectionHelper(sslPort: 5001);

                            _blazorHubConnection = new HubConnectionBuilder()
#if ANDROID
                                .WithUrl(devSslHelper.DevServerRootUrl + "/hubs/devicehub"
                                    , configureHttpConnection: o =>
                                    {
                                        o.HttpMessageHandlerFactory = m => devSslHelper.GetPlatformMessageHandler();
                                    }
                                )
#else
            .WithUrl(devSslHelper.DevServerRootUrl + "/hubs/devicehub")
#endif
                                .Build();

这个时候就不报 SSL 的连接错误了,可以方便的正常调试

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值