鸿蒙Harmony编程开发:HTTPS服务端证书四种校验方式

news2024/11/14 1:20:03

如果你还是使用HttpRequest的话,答案是否定的。但是,鸿蒙开发者很贴心的推出了远场通信服务,可以使用rcp模块的方法发起请求,并且在请求时指定服务端证书的验证方式,关键点就在SecurityConfiguration接口上,该接口的remoteValidation属性支持远程服务器证书的四种验证模式:

  • 'system':使用系统CA,默认值
  • 'skip':跳过验证
  • CertificateAuthority:选定CA
  • ValidationCallback:自定义证书校验

Talk is cheap, show you the code!

实现HTTPS服务端证书四种校验方式示例

本示例运行后的界面如下所示:

cke_54800.jpg

选择证书验证模式,在请求地址输入要访问的https网址,然后单击“请求”按钮,就可以在下面的日志区域显示请求结果。

下面详细介绍创建该应用的步骤。

步骤1:创建Empty Ability项目。

步骤2:在module.json5配置文件加上对权限的声明:

"requestPermissions": [
      {
        "name": "ohos.permission.INTERNET"
      }
    ]这里添加了获取互联网信息的权限。复制

步骤3:在Index.ets文件里添加如下的代码:

import util from '@ohos.util';
import picker from '@ohos.file.picker';
import fs from '@ohos.file.fs';
import { BusinessError } from '@kit.BasicServicesKit';
import { rcp } from '@kit.RemoteCommunicationKit';

@Entry
@Component
struct Index {
  //连接、通讯历史记录
  @State msgHistory: string = ''
  //请求的HTTPS地址
  @State httpsUrl: string = "https://47.**.**.***:8081/hello"
  //服务端证书验证模式,默认系统CA
  @State certVerifyType: number = 0
  //是否显示选择CA的组件
  @State selectCaShow: Visibility = Visibility.None
  //选择的ca文件
  @State caFileUri: string = ''
  scroller: Scroller = new Scroller()

  build() {
    Row() {
      Column() {
        Text("远场通讯HTTPS证书校验示例")
          .fontSize(14)
          .fontWeight(FontWeight.Bold)
          .width('100%')
          .textAlign(TextAlign.Center)
          .padding(10)

        Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
          Text("选择服务器HTTPS证书的验证模式:")
            .fontSize(14)
            .width(90)
            .flexGrow(1)
        }
        .width('100%')
        .padding(10)

        Flex({ justifyContent: FlexAlign.SpaceBetween, alignItems: ItemAlign.Center }) {
          Column() {
            Text('系统CA').fontSize(14)
            Radio({ value: '0', group: 'rgVerify' }).checked(true)
              .height(50)
              .width(50)
              .onChange((isChecked: boolean) => {
                if (isChecked) {
                  this.certVerifyType = 0
                }
              })
          }

          Column() {
            Text('指定CA').fontSize(14)
            Radio({ value: '1', group: 'rgVerify' }).checked(false)
              .height(50)
              .width(50)
              .onChange((isChecked: boolean) => {
                if (isChecked) {
                  this.certVerifyType = 1
                }
              })
          }

          Column() {
            Text('跳过验证').fontSize(14)
            Radio({ value: '2', group: 'rgVerify' }).checked(false)
              .height(50)
              .width(50)
              .onChange((isChecked: boolean) => {
                if (isChecked) {
                  this.certVerifyType = 2
                }
              })
          }

          Column() {
            Text('自定义验证').fontSize(14)
            Radio({ value: '3', group: 'rgVerify' }).checked(false)
              .height(50)
              .width(50)
              .onChange((isChecked: boolean) => {
                if (isChecked) {
                  this.certVerifyType = 3
                }
              })
          }
        }
        .width('100%')
        .padding(10)

        Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
          Text("服务端证书CA")
            .fontSize(14)
            .width(90)
            .flexGrow(1)

          Button("选择")
            .onClick(() => {
              this.selectCA()
            })
            .width(70)
            .fontSize(14)
        }
        .width('100%')
        .padding(10)
        .visibility(this.certVerifyType == 1 ? Visibility.Visible : Visibility.None)

        Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
          Text("请求地址:")
            .fontSize(14)
            .width(80)
          TextInput({ text: this.httpsUrl })
            .onChange((value) => {
              this.httpsUrl = value
            })
            .width(110)
            .fontSize(12)
            .flexGrow(1)
          Button("请求")
            .onClick(() => {
              this.doHttpRequest()
            })
            .width(60)
            .fontSize(14)
        }
        .width('100%')
        .padding(10)

        Scroll(this.scroller) {
          Text(this.msgHistory)
            .textAlign(TextAlign.Start)
            .padding(10)
            .width('100%')
            .backgroundColor(0xeeeeee)
        }
        .align(Alignment.Top)
        .backgroundColor(0xeeeeee)
        .height(300)
        .flexGrow(1)
        .scrollable(ScrollDirection.Vertical)
        .scrollBar(BarState.On)
        .scrollBarWidth(20)
      }
      .width('100%')
      .justifyContent(FlexAlign.Start)
      .height('100%')
    }
    .height('100%')
  }

  //自定义证书验证方式
  selfDefServerCertValidation: rcp.ValidationCallback = (context: rcp.ValidationContext) => {
    //此处编写证书有效性判断逻辑
    return true;
  }

  //生成rcp配置信息
  buildRcpCfg() {
    let caCert: rcp.CertificateAuthority = {
      content: this.getCAContent()
    }
    //服务器端证书验证模式
    let certVerify: 'system' | 'skip' | rcp.CertificateAuthority | rcp.ValidationCallback = "system"

    if (this.certVerifyType == 0) { //系统验证
      certVerify = 'system'
    } else if (this.certVerifyType == 1) { //选择CA证书验证
      certVerify =caCert
    } else if (this.certVerifyType == 2) { //跳过验证
      certVerify = 'skip'
    } else if (this.certVerifyType == 3) { //自定义证书验证
      certVerify = this.selfDefServerCertValidation
    }
    let secCfg: rcp.SecurityConfiguration = { remoteValidation: certVerify }
    let reqCfg: rcp.Configuration = { security: secCfg }
    let sessionCfg: rcp.SessionConfiguration = { requestConfiguration: reqCfg }
    return sessionCfg
  }

  //发起http请求
  doHttpRequest() {
    let rcpCfg = this.buildRcpCfg()
    let rcpSession: rcp.Session = rcp.createSession(rcpCfg)
    rcpSession.get(this.httpsUrl).then((response) => {
      if (response.body != undefined) {
        let result = buf2String(response.body)
        this.msgHistory += '请求响应信息: ' + result + "\r\n";
      }
    }).catch((err: BusinessError) => {
      this.msgHistory += `err: err code is ${err.code}, err message is ${JSON.stringify(err)}\r\n`;
    })
  }

  //选择CA证书文件
  selectCA() {
    let documentPicker = new picker.DocumentViewPicker();
    documentPicker.select().then((result) => {
      if (result.length > 0) {
        this.caFileUri = result[0]
        this.msgHistory += "select file: " + this.caFileUri + "\r\n";
      }
    }).catch((e: BusinessError) => {
      this.msgHistory += 'DocumentViewPicker.select failed ' + e.message + "\r\n";
    });
  }

  //加载CA文件内容
  getCAContent(): string {
    let caContent = ""
    try {
      let buf = new ArrayBuffer(1024 * 4);
      let file = fs.openSync(this.caFileUri, fs.OpenMode.READ_ONLY);
      let readLen = fs.readSync(file.fd, buf, { offset: 0 });
      caContent = buf2String(buf.slice(0, readLen))
      fs.closeSync(file);
    } catch (e) {
      this.msgHistory += 'readText failed ' + e.message + "\r\n";
    }
    return caContent
  }
}


//ArrayBuffer转utf8字符串
function buf2String(buf: ArrayBuffer) {
  let msgArray = new Uint8Array(buf);
  let textDecoder = util.TextDecoder.create("utf-8");
  return textDecoder.decodeWithStream(msgArray)
}

步骤4:编译运行,可以使用模拟器或者真机。

步骤5:选择默认“系统CA”,输入请求网址(假设web服务端使用的是自签名证书),然后单击“请求”按钮,这时候会出现关于数字证书的错误信息,如图所示:

cke_63643.jpg

步骤6:选择“指定CA”类型,然后单击出现的“选择”按钮,可以在本机选择CA证书文件,然后单击“请求”按钮:

cke_129996.jpg

可以看到,得到了正确的请求结果。

步骤7:选择“跳过验证”类型,然后然后单击“请求”按钮:

cke_159268.jpg

也得到了正确的请求结果。

步骤8:选择“自定义验证”类型,然后然后单击“请求”按钮:

cke_253658.jpg

也得到了正确的请求结果。

关键功能分析

关键点主要有两块,第一块是设置验证模式:

    //服务器端证书验证模式
    let certVerify: 'system' | 'skip' | rcp.CertificateAuthority | rcp.ValidationCallback = "system"

    if (this.certVerifyType == 0) { //系统验证
      certVerify = 'system'
    } else if (this.certVerifyType == 1) { //选择CA证书验证
      certVerify =caCert
    } else if (this.certVerifyType == 2) { //跳过验证
      certVerify = 'skip'
    } else if (this.certVerifyType == 3) { //自定义证书验证
      certVerify = this.selfDefServerCertValidation
    }
    let secCfg: rcp.SecurityConfiguration = { remoteValidation: certVerify }
    let reqCfg: rcp.Configuration = { security: secCfg }
    let sessionCfg: rcp.SessionConfiguration = { requestConfiguration: reqCfg }
    return sessionCfg
  }

这个比较好理解,第二块是自定义证书验证的方法:

  //自定义证书验证方式
  selfDefServerCertValidation: rcp.ValidationCallback = (context: rcp.ValidationContext) => {
    //此处编写证书有效性判断逻辑
    return true;
  }

这里为简单起见,自定义规则是所有的验证都通过,读者可以根据自己的需要来修改,比如不验证证书的有效期。

最后

小编在之前的鸿蒙系统扫盲中,有很多朋友给我留言,不同的角度的问了一些问题,我明显感觉到一点,那就是许多人参与鸿蒙开发,但是又不知道从哪里下手,因为资料太多,太杂,教授的人也多,无从选择。有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以有一份实用的鸿蒙(HarmonyOS NEXT)资料用来跟着学习是非常有必要的。 

为了确保高效学习,建议规划清晰的学习路线,涵盖以下关键阶段:

希望这一份鸿蒙学习资料能够给大家带来帮助~


 鸿蒙(HarmonyOS NEXT)最新学习路线

该路线图包含基础技能、就业必备技能、多媒体技术、六大电商APP、进阶高级技能、实战就业级设备开发,不仅补充了华为官网未涉及的解决方案

路线图适合人群:

IT开发人员:想要拓展职业边界
零基础小白:鸿蒙爱好者,希望从0到1学习,增加一项技能。
技术提升/进阶跳槽:发展瓶颈期,提升职场竞争力,快速掌握鸿蒙技术

2.视频学习资料+学习PDF文档

(鸿蒙语法ArkTS、TypeScript、ArkUI教程……)

 纯血版鸿蒙全套学习资料(面试、文档、全套视频等)

                   

鸿蒙APP开发必备

​​

总结

参与鸿蒙开发,你要先认清适合你的方向,如果是想从事鸿蒙应用开发方向的话,可以参考本文的学习路径,简单来说就是:为了确保高效学习,建议规划清晰的学习路线

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2068573.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

K8S故障排查可视化指南 —— 筑梦之路

在线查看 中文版:http://114.132.181.71:8080/book/71 英文版:http://114.132.181.71:8080/book/70 A visual guide on troubleshooting Kubernetes deployments

Python二级(易错点讲解)

今天在做真题时,遇到了不少坑的地方,跟大家一起分享,感谢大家观看和关注。 祝大家都能在20多天后顺利通过Python二级。 一.continue循环 大家都知道continue关键字在编程中用于跳过当前循环的剩余迭代并直接开始下一次迭代。 好,…

怎么整合spring security和JWT

什么是spring security spring security是一个安全框架,它里面有过滤器链,可以多次过滤,其实他可以给前端的cookie传入一个jsessionid,都可以不使用jwt也能完成校验 第一步:导入依赖 <!-- springboot security --> <dependency><groupId>org.springframew…

整合Spring和Mybatis(在整合DBCP基础上修改)

整合DBCP请参考主页文章spring整合DBCP 前期准备工作 删除dao层的实现类&#xff0c;只留下接口即可。 在resource文件夹下导入dao层对应的xml文件以及mybatis的核心配置文件&#xff0c;配置文件中只写加载映射文件的代码即可&#xff0c;如下所示 <?xml version"…

Kakfa的核心概念-Replica副本(kafka创建topic并指定分区和副本的两种方式)

Kakfa的核心概念-Replica副本&#xff08;kafka创建topic并指定分区和副本的两种方式&#xff09; 1、kafka命令行脚本创建topic并指定分区和副本2、springboot集成kafka创建topic并指定分区和副本2.1、springboot集成kafka2.1.1、springboot集成kafka创建topic并指定5个分区和…

java BIO NIO AIO

结合JavaGuideIO部分内容食用更佳 在Java中&#xff0c;I/O&#xff08;输入/输出&#xff09;操作主要有三种模型&#xff1a;BIO&#xff08;Blocking I/O&#xff0c;阻塞I/O&#xff09;、NIO&#xff08;Non-blocking I/O&#xff0c;非阻塞I/O&#xff09;和AIO&#x…

怎样写好提示词(Prompt) 一

提示工程是一门新兴的学科&#xff0c;专注于以最佳实践构建LLM的最佳输入&#xff0c;从而尽可能以程序化方式生成目标输出。AI工程师必须知道如何与AI进行交互&#xff0c;以获取可用于应用程序的有利结果。此外&#xff0c;AI工程师还必须知道如何正确提问和编写高质量的提示…

python小游戏——躲避球(可当课设)

游戏简介&#xff1a; 没有美术&#xff0c;画面简洁&#xff08;懒得做&#xff09;。玩家控制小球躲避敌人&#xff08;上下左右&#xff0c;闪避&#xff09;&#xff0c;敌人体积越大速度越慢&#xff0c;随机生成道具球&#xff08;目前只有生命球&#xff09;&#xff0…

第T9周:猫狗识别2

>- **&#x1f368; 本文为[&#x1f517;365天深度学习训练营]) 中的学习记录博客** >- **&#x1f356; 原作者&#xff1a;[K同学啊](K同学啊)** 一、前期工作 1. 设置GPU import tensorflow as tfgpus tf.config.list_physical_devices("GPU")if gpus:t…

Linux权限概念与思想,能深度理解“权限”,看这一篇就够啦

目录 一、Linux权限的概念 a.什么是权限&#xff1f; b.权限的本质 c.Linux中的用户 1.从root用户切换到普通用户user&#xff1a; 2.从普通用户user切换到root用户&#xff1a; 3.我不想直接变成root&#xff0c;但是我就是想以root的身份执行一个工作&#xff1f; 4.L…

EXCEL 分组后找出满足条件的行拼接起来

Excel某表格有四列&#xff0c;其中第2列是分组列。 ABCD11a1yet22a2done33a3yet44b1done55b2done66b3done77b4yet88b5done 现在要按第2列分组&#xff0c;找到每组第4列等于"done"的行&#xff0c;将这些行的第3列用逗号拼起来&#xff0c;再与分组名、行号组成新…

Unity动画模块 之 动画层混合

本文仅作笔记学习和分享&#xff0c;不用做任何商业用途 本文包括但不限于unity官方手册&#xff0c;unity唐老狮等教程知识&#xff0c;如有不足还请斧正 1.动画层 动画层 - Unity 手册&#xff0c;动画层的作用 混合模式 覆盖和叠加模式&#xff0c;很好理解吧 权重 到底…

若依权限控制前端+后端实现思路梳理(PreAuthorize、hasPermi、v-hasPermi)

一、权限控制引发的思考 引言 最近接手了公司的一个项目&#xff0c;实施反馈说&#xff0c;客户那边要求对不同的权限的用户操作权限做限制。场景就是&#xff0c;比如一个项目列表&#xff0c;这部分数据有可能是针对某个公司某个部门的&#xff0c;对应不同的部门用户能看…

云岚到家 第一天

你的项目是做什么业务的&#xff1f; 家政服务&#xff0c;我的项目是一个家政o2o平台。o2o&#xff08;Online To Offline&#xff09;是将线下商务的机会与互联网的技术结合 什么商业模式&#xff1a; 项目涉及哪些角色&#xff1f; 本项目涉及如下角色&#xff1a; 家政…

技术前沿:WebRTC与H.265编码的兼容性挑战与应对策略

WebRTC&#xff08;Web Real-Time Communication&#xff09;是一种支持网页浏览器进行实时语音通话、视频聊天以及P2P文件共享的技术。然而&#xff0c;标准的WebRTC API在大多数浏览器中默认并不支持H.265&#xff08;也称为HEVC&#xff0c;高效视频编码&#xff09;编码。这…

Android 中native C++创建thread的几种方式

Android native 开发&#xff0c;工作中最常用的两种创建thread的方法&#xff0c;总结如下&#xff1a; 使用 pthread 库 &#xff08;1&#xff09;概念&#xff1a;它是一套在类 Unix 操作系统上进行多线程编程的接口&#xff0c; 而android 基于Linux , Linux就是一个类 U…

用序列模型(GPT Bert Transformer等)进行图像处理的调研记录

Visual Autoregressive Modeling: Scalable Image Generation via Next-Scale Prediction 北大和字节团队的一篇VLM&#xff0c;在生成任务上&#xff0c;用GPT范式&#xff0c;声称在FID上超过了DIT&#xff0c;SD3和SORA。开源。首先是multi-scale的VQVAE&#xff0c;然后是…

Datawhale X 李宏毅苹果书 AI夏令营 学习笔记(一)

局部极小值与鞍点 在优化过程中&#xff0c;模型可能会遇到局部极小值(local minima)或鞍点(saddle point)&#xff0c;这些位置梯度为零&#xff0c;使得模型停止进步或训练缓慢。 局部极小值是损失函数的局部最低点&#xff0c;而鞍点则是梯度为零但不是局部极小/极大值的点…

Leetcode JAVA刷刷站(80)删除有序数组中的重复项 ||

一、题目概述 二、思路方向 为了解决这个问题&#xff0c;我们可以使用双指针技术。一个指针&#xff08;我们称之为i&#xff09;用于遍历数组&#xff0c;另一个指针&#xff08;我们称之为j&#xff09;用于记录不重复或只重复一次的元素应该放置的位置。同时&#xff0c;我…

创新实践:流媒体服务器如何推动WebRTC支持H.265及JS硬软解码(MSE硬解、WASM软解)

为了实现这一全面的解决方案&#xff0c;我们投入了近半年的时间进行调研与研发。我们的主要目标是&#xff1a;让流媒体服务器能够直接传输H.265编码的视频&#xff0c;而无需将其转码为H.264&#xff0c;从而使Chrome浏览器能够无缝解码并播放H.265视频。 值得注意的是&#…