CAP项目集成带身份和证书验证的MongoDB

cap,项目,集成,身份,证书,验证,mongodb · 浏览次数 : 100

小编点评

本文介绍了如何在CAP中集成带基础身份验证(用户名/密码)+SSL根证书验证的MongoDB,方便CAP能够正常连接MongoDB并生成本地消息表。 **主要内容:** * CAP官方文档介绍了如何使用mongodb连接MongoDB并生成本地消息表。 * 作者展示了如何将mongodb连接和发送消息到本地消息表中。 * 详细介绍了如何设置SSL根证书验证,确保安全连接。 * 总结了如何使用mongodb连接MongoDB并生成本地消息表。 **主要代码:** ```csharp // MongoDB连接配置 DbConnection connection = DbConnUtil.GetMongoDbConnectionString(config); // MongoDB数据库名称 string databaseName = config["MongoDatabaseConfigs:DatabaseName"]; // 发送消息到本地消息表 mongoPublish.Send(new Message(databaseName, "msg.published", 100)); // 获取本地消息表 var message = mongoReceive.Receive(new Message(databaseName, "msg.received", 100)); ``` **其他说明:** * 上述代码展示了如何设置SSL根证书验证,确保安全连接。 * 作者展示了如何设置mongodb连接和发送消息到本地消息表中。 * 总结了如何使用mongodb连接MongoDB并生成本地消息表。

正文

大家好,我是Edison。

最近,在在ASP.NET 6中使用CAP事件总线时,碰到了这样一个需求:微服务采用的是MongoDB,而且还是带身份验证 和 SSL根证书验证的。由于目前网上能找到的资料,都是不带身份验证的MongoDB,现在网络信息安全越来越被重视,那么就需要自己研究一番了。

CAP.MongoDB组件

CAP是一个开源的事件总线项目,在.NET社区已经十分流行了,它提供了多种存储方式:MSSQL, MySQL, PgSQL,MongoDB等,这里我们主要关注MongoDB。快速安装CAP.MongoDB组件:

PM> Install-Package DotNetCore.CAP.MongoDB

快速集成CAP.MongoDB组件(StartUp.cs):

public void ConfigureServices(IServiceCollection services)
{
    // ...
​
    services.AddCap(x =>
    {
        x.UseMongoDB(opt=>{
            //MongoDBOptions
        });
        // x.UseXXX ...
    });
}

目前CAP提供的Options如下:

也就是说,CAP的Option只提供了一个DatabaseConnection选项,让我们自己构造Mongo链接字符串供CAP使用。

那么,我们就需要准确地构造这个Mongo连接字符串了。

这里,我们以之前分享的一篇文章《在ASP.NET 6中使用工作单元操作MongoDB》为基础,不熟悉的朋友可以先看看这篇文章。

前提条件/准备工作

这里我们假设在appsettings中我们针对MongoDB的配置项如下格式:

"MongoDatabaseConfigs": {
    "Servers": "xxx01.server.net,xxx02.server.net,xxx03.server.net",
    "Port": 27017, // optional, default : 27017
    "ReplicaSetName": "myrs",
    "DatabaseName": "TEST_DB",
    "AuthDatabaseName": "admin", // optional, default: admin
    "ApplicationName": "Todo",
    "UserName": "test_dev_user",
    "Password": "test_dev_password",
    "UseTLS": true,  // optional, default : false
    "AllowInsecureTLS": true, // optional, default : true
    "SslCertificatePath": "/etc/pki/tls/certs/MyCustomCA.cer"
}

配置项中给出了UserName、Password 还有 SSL证书的路径,这些都是需要构造到连接字符串中的。当然,在Kubernetes中,都建议放到Secret中去。

核心工作:封装构造连接字符串的方法

这里我们封装一个生成MongoDB连接字符串的静态方法,用于读取appsettings中的配置项,并帮我们生成CAP可以用的MongoDB连接字符串:

public static class DbConnUtil
{
    // Const Settings for Mongo
    private const int DEFAULT_CONNECT_TIMEOUT_MS = 10000; // 10s
    private const int DEFAULT_SERVER_SELECTION_TIMEOUT_MS = 5000; // 5s
    private const string DEFAULT_AUTH_MECHANISM = "SCRAM-SHA-256"; // SCRAM-SHA-256
    private const string DEFAULT_READ_PREFERENCE = "primaryPreferred"; // Primary Preferred
    private const string DEFAULT_SSL_INVALID_HOSTNAME_ALLOWED = "true"; // Allow Invalid HostName for SSL

    /// <summary>
    /// 获取MongoDB数据库连接字符串
    /// 需要在配置文件中提前根据指定Key进行设置
    /// </summary>
    public static string GetMongoDbConnectionString(IConfiguration config)
    {
        var servers = config["MongoDatabaseConfigs:Servers"];
        var port = config["MongoDatabaseConfigs:Port"] ?? "27017";
        if (string.IsNullOrWhiteSpace(servers))
            throw new ArgumentNullException("Mongo Servers Configuration is Missing!");
        var mongoServers = servers.Split(',');

        // Basic Auth
        var userName = config["MongoDatabaseConfigs:UserName"];
        var password = config["MongoDatabaseConfigs:Password"];
        if (string.IsNullOrWhiteSpace(userName) || string.IsNullOrWhiteSpace(password))
            throw new ArgumentNullException("Mongo Account Configuration is Missing!");

        // Uri
        var replicaName = config["MongoDatabaseConfigs:ReplicaSetName"];
        var authDatabaseName = config["MongoDatabaseConfigs:AuthDatabaseName"] ?? "admin";
        var mongoUriBuilder = new StringBuilder();
        mongoUriBuilder.Append($"mongodb://{userName}:{password}@");
        for (int i = 0; i < mongoServers.Length; i++)
        {
            if (i < mongoServers.Length - 1)
            {
                mongoUriBuilder.Append($"{mongoServers[i]}:{port},");
            }
            else
            {
                mongoUriBuilder.Append($"{mongoServers[i]}:{port}/?");
            }
        }

        // Settings
        var applicationName = config["MongoDatabaseConfigs:ApplicationName"];
        mongoUriBuilder.Append($"replicaSet={replicaName}");
        mongoUriBuilder.Append($"&appName={applicationName}");
        mongoUriBuilder.Append($"&authSource={authDatabaseName}");
        mongoUriBuilder.Append($"&authMechanism={DEFAULT_AUTH_MECHANISM}");
        mongoUriBuilder.Append($"&connectTimeoutMS={DEFAULT_CONNECT_TIMEOUT_MS}"); 
        mongoUriBuilder.Append($"&serverSelectionTimeoutMS={DEFAULT_SERVER_SELECTION_TIMEOUT_MS}");
        mongoUriBuilder.Append($"&readPreference={DEFAULT_READ_PREFERENCE}");

        // TLS/SSL Auth
        var useTLS = Convert.ToBoolean(config["MongoDatabaseConfigs:UseTLS"] ?? "false");
        if (useTLS)
        {
            var allowInsecureTls = Convert.ToBoolean(config["MongoDatabaseConfigs:AllowInsecureTLS"] ?? "true");
            var sslCertificatePath = config["MongoDatabaseConfigs:SslCertificatePath"];
            
            mongoUriBuilder.Append($"&ssl={useTLS}");
            mongoUriBuilder.Append($"&net.ssl.CAFile={sslCertificatePath}");
            mongoUriBuilder.Append($"&net.ssl.allowInvalidCertificates={DEFAULT_SSL_INVALID_HOSTNAME_ALLOWED}");
        }

        return mongoUriBuilder.ToString();
    }
}

最终可以生成的连接字符串为:

mongodb://test_dev_user:test_dev_password@xxx01:27017.server.net,xxx02.server.net:27017,xxx03.server.net:27017/?replicaSet=myrs&appName=Todo&authSource=admin&authMechanism=SCRAM-SHA-256&connectTimeoutMS=10000&serverSelectionTimeoutMS=5000&readPreference=primaryPreferred&ssl=True&net.ssl.CAFile=/etc/pki/tls/certs/MyCustomCA.cer&net.ssl.allowInvalidCertificates=true

ASP.NET Core集成CAP

这里我们使用刚刚封装的方法来生成Mongo连接字符串,来快速集成CAP:

public static IServiceCollection AddApplicationEventBus(this IServiceCollection services, IConfiguration config)
{
    ......
    // CAP EventBus
    services.AddCap(option =>
    {
        // Transport
        option.UseKafka(option =>
        {
            option.Servers = config["EventBusConfigs:KafkaServers"]
                ?? throw new ArgumentException("EventBusConfigs:KafkaServers must be set!");
            option.ConnectionPoolSize = int.Parse(config["EventBusConfigs:CapConnectionPoolSize"]
                ?? ApplicationDefaultSettings.Default_ConnectionPool_Size);
            option.CustomHeaders = e => new List<KeyValuePair<string, string>>
                    {
                        new KeyValuePair<string, string>(Headers.MessageId, SnowflakeId.Default().NextId().ToString()),
                        new KeyValuePair<string, string>(Headers.MessageName, e.Topic)
                    };

            if (Convert.ToBoolean(config["EventBusConfigs:EnableAuthorization"] ?? "false"))
            {
                var userName = config["EventBusConfigs:SaslUserName"];
                var passWord = config["EventBusConfigs:SaslPassword"];

                if (string.IsNullOrWhiteSpace(userName) || string.IsNullOrWhiteSpace(passWord))
                    throw new ArgumentNullException("Kafka username or password can't be null!");

                option.MainConfig.Add(KafkaMainConfigKey.SECURITY_PROTOCOL, KafkaProtocol.SASL_SSL);
                option.MainConfig.Add(KafkaMainConfigKey.SASL_MECHANISM, KafkaAuthMechanism.PLAIN);
                option.MainConfig.Add(KafkaMainConfigKey.SASL_USERNAME, userName);
                option.MainConfig.Add(KafkaMainConfigKey.SASL_PASSWORD, passWord);

                if (!string.IsNullOrWhiteSpace(config["EventBusConfigs:SslCertificatePath"]))
                    option.MainConfig.Add(KafkaMainConfigKey.SSL_CA_LOCATION, config["EventBusConfigs:SslCertificatePath"]);
                if (!string.IsNullOrWhiteSpace(config["EventBusConfigs:EnableSslCertificateVerification"]))
                    option.MainConfig.Add(KafkaMainConfigKey.ENABLE_SSL_CERT_VERIFICATION, config["EventBusConfigs:EnableSslCertificateVerification"]);
            }
        });
        option.SucceedMessageExpiredAfter = 3600 * 24 * int.Parse(config["EventBusConfigs:CapSuccessMsgExpireDays"];
        // Storage
        option.UseMongoDB(option =>
        {
            option.DatabaseConnection = DbConnUtil.GetMongoDbConnectionString(config);
            option.DatabaseName = config["MongoDatabaseConfigs:DatabaseName"] 
                ?? throw new ArgumentException("MongoDatabaseConfigs:DatabaseName must be set!");
            option.PublishedCollection = "msg.published";
            option.ReceivedCollection = "msg.received";
        });
    });

    ......

    return services;
}

小结

本文我们了解了如何在CAP中集成带基础身份验证(用户名/密码)+SSL根证书验证的MongoDB,方便CAP能够正常连接MongoDB并生成本地消息表,在网络信息安全越来越重视的现在,相信会对你使用CAP+MongoDB有一定帮助!

参考资料

CAP官方文档:https://cap.dotnetcore.xyz/user-guide/en/storage/mongodb/
MongoDB官方文档:https://www.mongodb.com/docs/v5.0/security/

 

与CAP项目集成带身份和证书验证的MongoDB相似的内容:

CAP项目集成带身份和证书验证的MongoDB

最近,在使用CAP事件总线时,碰到了这样一个需求:微服务采用的是MongoDB,而且还是带身份验证 和 SSL根证书验证的。由于目前网上能找到的资料,都是不带身份验证的MongoDB,现在网络信息安全越来越被重视,那么就需要自己研究一番了。

CAP 8.2 版本发布通告

前言 今天我们很高兴宣布 CAP 发布 8.2 版本正式版,我们在这个版本中主要致力于对订阅着并行执行的特性提供支持,同时添加了对在订阅者中对消息头的控制行为。 下面,具体看一下我们新版本的功能吧。 总览 可能有些人还不知道 CAP 是什么,老规矩来一个简介。 CAP 是一个用来解决微服务或者分布式

分布式事务的几种实现方式

## 基础理论 ### CAP理论 一致性(Consistency) :在分布式系统中所有的数据备份,在同一时刻都保持一致状态,如无法保证状态一致,直接返回错误; 可用性(Availability):在集群中一部分节点故障,也能保证客户端访问系统并得到正确响应,允许一定时间内数据状态不一致; 分区容

Asp .Net Core 系列:集成 CAP + RabbitMQ + MySQL(含幂等性)

简介 官网:https://cap.dotnetcore.xyz/ CAP 是什么? 是一个 EventBus,同时也是一个在微服务或者 SOA 系统中解决分布式事务问题的一个框架。它有助于创建可扩展,可靠并且易于更改的微服务系统。 什么是 EventBus? 事件总线是一种机制,它允许不同的组件彼

Fast Walsh Transform 学习笔记 | FWT

本文中使用 \(\cap\) 表示按位与,用 \(\cup\) 表示按位或 Part 1. 与/或 卷积 First. 问题引入 给定长度为 \(2^n\) 的数列 \(A,B\),求 \(C_i = \sum_{j \cup k = i} A_j \times B_k\) 显然有 \(O(4^n)

[转帖]分布式必备理论基础:CAP和BASE

http://blog.itpub.net/70024420/viewspace-2926174/ 大家好,我是老三,今天是没有刷题的一天,心情愉悦,给大家分享两个简单的知识点:分布式理论中的CAP和BASE。 CAP理论 什么是CAP CAP原则又称CAP定理,指的是在一个分布式系统中,Consi

.NET周报【12月第1期 2022-12-08】

国内文章 CAP 7.0 版本发布通告 - 支持延迟消息,性能炸了? https://www.cnblogs.com/savorboard/p/cap-7-0.html) 今天,我们很高兴宣布 CAP 发布 7.0 版本正式版,我们在这个版本中带来了大批新特性以及对性能的优化和改进。 使用.NET7

Appium新版本引发的一个问题

# Appium新版本引发的一个问题 # 准备工作 ## 测试代码 ```python from appium import webdriver des_cap = {'platformName': 'android'} driver = webdriver.Remote(command_execu

[转帖]docker安装ntp服务器并校时

https://www.javaclub.cn/server/61611.html 内网环境下,几台机器可能出现时间不一致的情况,导致数据时间不一致。使用docker安装ntp服务器简单快捷、不依赖具体操作系统环境。 1.安装命令: docker run -d --net=host --cap-ad

造轮子之EventBus

前面基础管理的功能基本开发完了,接下来我们来优化一下开发功能,来添加EventBus功能。EventBus也是我们使用场景非常广的东西。这里我会实现一个本地的EventBus以及分布式的EventBus。分别使用MediatR和Cap来实现。 现在简单介绍一下这两者:MediatR是一个轻量级的中介