使用reqwest开发HTTP客户端进行双向认证请求

简介

reqwest是一个用于Rust的HTTP客户端库,它提供了简单易用的API来发送HTTP请求和处理响应

接下来介绍下如何使用reqwest进行https的双向认证请求

同时文章使用Rust中的actix_web框架搭建双向认证的Web服务器介绍了使用actix_web如何搭建一个双向认证的Web服务器

依赖

[dependencies]
reqwest = {version = "0.12.9", features = ["native-tls"]}
tokio = {version = "1.42.0", features = ["full"]}

以上为Cargo.toml文件中添加的依赖和配置的features

加载验证服务端的CA证书

    let mut buf = Vec::new();
    _ = File::open("C:\\Users\\zuolu\\SourceCode\\rust_client\\ca.crt")
        .unwrap()
        .read_to_end(&mut buf)
        .unwrap();
        
 	let ca_cert = Certificate::from_pem(&buf).unwrap();

要对服务端证书进行验证只需要加载为服务端签署证书的CA证书即可,非常简单直观。注意这里需要v3版本的证书

加载服务端验证客户端的证书

    let mut pem = Vec::new();
    let mut pkcs8 = Vec::new();
    _ = File::open("C:\\Users\\zuolu\\SourceCode\\rust_client\\client.crt")
        .unwrap()
        .read_to_end(&mut pem)
        .unwrap();
    _ = File::open("C:\\Users\\zuolu\\SourceCode\\rust_client\\client_pkcs8.key")
        .unwrap()
        .read_to_end(&mut pkcs8)
        .unwrap();
    let identity: Identity = Identity::from_pkcs8_pem(&pem, &pkcs8).unwrap();

因为需要进行双向认证,所以客户端也需要证书来告知服务端自己的身份。这里client.crtclient_pkcs8.key分别是客户端的证书和私钥。对应的,在服务端你需要有能够验证client.crt的CA证书

构造ClientBuilder和Client

    let client_build = ClientBuilder::new()
        // .danger_accept_invalid_certs(true)
        // .danger_accept_invalid_hostnames(true)
        // .use_rustls_tls()
        .identity(identity)
        .add_root_certificate(ca_cert);
        
    let client = client_build.build().unwrap();

使用前面得到的ca_cert identity构造一个ClientBuilder

这个地方我遇到了几个坑。首先是最初在指定reqwest 的features 时没有采用native-tls,而是使用的rustls-tls。然后在通过ClientBuilder生成Client时出现错误kind: Builder, source: "incompatible TLS identity type"。一番查找之后发现issues中有提到构造ClientBuilder时.use_rustls_tls()可以解决。添加后确实也成功通过ClientBuilder构造出了Client

但是在通过Client发送数据时出现kind: Other, error: Custom { kind: InvalidData, error: InvalidCertificate(NotValidForName) } }的错误。最后是通过将features 指定为native-tls解决

请求

    let res = client.get("https://example.com:9999/zuoluo_windows")
        .send()
        .await
        .unwrap();

    let body = res.text().await.unwrap();
    println!("{}", body);

最后,通过构造的client对服务端进行请求,值得注意的是因为服务端没有监听在443上,所以这里需要明确指定一下服务端监听的端口

同时不要忘了把你电脑上的hosts改一下,将域名example.com指向127.0.0.1即可,windows电脑的hosts位置为C:\Windows\System32\drivers\etc\hosts,在文件中添加

127.0.0.1       example.com

最后运行抓包
在这里插入图片描述

可以看到成功的建立了加密连接

最后客户端完整的代码贴在下面

客户端demo完整代码

use std::{fs::File, io::Read};

use reqwest::{Certificate, ClientBuilder, Identity};

#[tokio::main]
async fn main() {
    let mut buf = Vec::new();
    _ = File::open("C:\\Users\\zuolu\\SourceCode\\rust_client\\ca.crt")
        .unwrap()
        .read_to_end(&mut buf)
        .unwrap();

    let ca_cert = Certificate::from_pem(&buf).unwrap();

    let mut pem = Vec::new();
    let mut pkcs8 = Vec::new();
    _ = File::open("C:\\Users\\zuolu\\SourceCode\\rust_client\\client.crt")
        .unwrap()
        .read_to_end(&mut pem)
        .unwrap();
    _ = File::open("C:\\Users\\zuolu\\SourceCode\\rust_client\\client_pkcs8.key")
        .unwrap()
        .read_to_end(&mut pkcs8)
        .unwrap();
    let identity: Identity = Identity::from_pkcs8_pem(&pem, &pkcs8).unwrap();

    let client_build = ClientBuilder::new()
        // .danger_accept_invalid_certs(true)
        // .danger_accept_invalid_hostnames(true)
        // .use_rustls_tls()
        .identity(identity)
        .add_root_certificate(ca_cert);
    
    let client = client_build.build().unwrap();

    let res = client.get("https://example.com:9999/zuoluo_windows")
        .send()
        .await
        .unwrap();

    let body = res.text().await.unwrap();
    println!("{}", body);
    // println!("body = {body:?}");
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zl.rs

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值