.NET Core应用如何通过SSL访问MongoDB?
大家好,我是Edison。
最近有一个ASP.NET Core通过SSL证书访问MongoDB的需求,但是在网上发现资料很少,于是调查了一番,做了如下的笔记,希望对你有用。
背景
在实际场景中,开发环境的MongoDB服务器一般没有要求通过SSL方式来登陆,但是生产环境的MongoDB服务器通常都会基于安全要求基于SSL方式来访问,这就要求客户端应用需要通过SSL证书来和MongoDB服务器进行通信验证后才能正常读取和写入数据。
那么,在ASP.NET Core应用中应该如何修改匹配呢?今天,我们就来看一看。
修改
通过学习MongoDB.Driver后,在实例化MongoClient时可以通过传递一个MongoClientSettings类来进行自定义参数的实例化,而这个MongoClientSettings类提供的参数比较丰富,我们可以将这些参数配置在appsettings中进行分环境的自定义。
var mongoClient = new MongoClient(new MongoClientSettings());
因此,我们可以写一个MongoSettings类来读取appsettings中的配置生成一个MongoClientSettings,这里给出一个参考示例。
using MongoDB.Driver; using System.Security.Cryptography.X509Certificates; namespace EDT.Todo.Data.Persistance { /// <summary> /// Generate MongoClientSettings /// </summary> public class MongoSettings { public string Servers { get; set; } public int Port { get; set; } = 27017; public string ReplicaSetName { get; set; } public string DatabaseName { get; set; } public string DefaultCollectionName { get; set; } = string.Empty; public string ApplicationName { get; set; } public string UserName { get; set; } public string Password { get; set; } public string AuthDatabaseName { get; set; } = string.Empty; public string CustomProperties { get; set; } = string.Empty; public bool UseTLS { get; set; } = false; public bool AllowInsecureTLS { get; set; } = true; public string ClientCertificatePath { get; set; } = string.Empty; public bool StoreCertificateInKeyStore { get; set; } = false; public MongoClientSettings GetMongoClientSettings() { if (string.IsNullOrWhiteSpace(Servers)) throw new ArgumentNullException("Mongo Servers Configuration is Missing!"); if (string.IsNullOrWhiteSpace(UserName) || string.IsNullOrWhiteSpace(Password)) throw new ArgumentNullException("Mongo Account Configuration is Missing!"); // Base Configuration MongoClientSettings settings = new MongoClientSettings { ApplicationName = ApplicationName, ReplicaSetName = ReplicaSetName }; // Credential if (string.IsNullOrWhiteSpace(AuthDatabaseName)) settings.Credential = MongoCredential.CreateCredential(DatabaseName, UserName, Password); else settings.Credential = MongoCredential.CreateCredential(AuthDatabaseName, UserName, AuthDatabaseName); // Servers var mongoServers = Servers.Split(",", StringSplitOptions.RemoveEmptyEntries).ToList(); if (mongoServers.Count == 1) { settings.Server = new MongoServerAddress(mongoServers.First(), Port); settings.DirectConnection = true; } if (mongoServers.Count > 1) { var mongoServerAddresses = new List<MongoServerAddress>(); foreach (var mongoServer in mongoServers) { var mongoServerAddress = new MongoServerAddress(mongoServer, Port); mongoServerAddresses.Add(mongoServerAddress); } settings.Servers = mongoServerAddresses; settings.DirectConnection = false; } // SSL if (UseTLS) { settings.UseTls = true; settings.AllowInsecureTls = AllowInsecureTLS; if (string.IsNullOrWhiteSpace(ClientCertificatePath)) throw new ArgumentNullException("ClientCertificatePath is Missing!"); var certs = new List<X509Certificate> { new X509Certificate2(ClientCertificatePath) }; settings.SslSettings = new SslSettings(); settings.SslSettings.ClientCertificates = certs; settings.SslSettings.EnabledSslProtocols = System.Security.Authentication.SslProtocols.Tls13; } return settings; } } }
对于原有的Repository类,我们则需要做一点点修改,从IoC容器中获取MongoSettings的实例,并通过调用GetMongoClientSettings方法获取到生成的这个具体的MongoClientSettings对象:
public class TodoItemRepository : ITodoItemRepository { private readonly ILogger<TodoItemRepository> _logger; private readonly IMongoCollection<TodoItem> _todoItems; public TodoItemRepository(MongoSettings settings, ILogger<TodoItemRepository> logger) { var mongoClient = new MongoClient(settings.GetMongoClientSettings()); var mongoDatabase = mongoClient.GetDatabase(settings.DatabaseName); _todoItems = mongoDatabase.GetCollection<TodoItem>(settings.DefaultCollectionName); _logger = logger; } ...... }
在Program.cs中将MongoSettings和appsettings中的配置绑定:
builder.Services.Configure<MongoSettings>( builder.Configuration.GetSection("MongoDatabase")); builder.Services.AddSingleton(sp => sp.GetRequiredService<IOptions<MongoSettings>>().Value); ...... builder.Services.AddSingleton<ITodoItemRepository, TodoItemRepository>();
针对Development环境的appsettings:
{ ...... "MongoDatabase": { "Servers": "dev.mongodb01.com,dev.mongodb01.com,dev.mongodb01.com", "Port": 27017, "ReplicaSetName": "testrplica", "DatabaseName": "TestDB", "DefaultCollectionName": "TodoItems", "ApplicationName": "Todo", "UserName": "dev_mongo_user", "Password": "passwordfordevuser", "UseTLS": false } }
针对Production环境的appsettings:
{ ...... "MongoDatabase": { "Servers": "prd.mongo01.com,prd.mongo02.com,prd.mongo03.com", "Port": 27007, "ReplicaSetName": "testreplica", "DatabaseName": "TestDB", "DefaultCollectionName": "TodoItems", "ApplicationName": "Todo", "UserName": "prd_mongo_user", "Password": "passwordforprduser", "UseTLS": true, "AllowInsecureTLS": true, "ClientCertificatePath": "resources/certificates/intranet_server_ca.cer" } }
既然是通过证书访问,那么我们得告诉ASP.NET Core这个证书放在什么位置,本文示例是放在这个ASP.NET Core应用目录下的,在实际中建议由运维管理员统一放在一个中心服务器位置,挂载到容器内部可以访问,从而保证证书的安全。如果使用了K8s,还可以将证书作为Secret统一存放。
小结
本文介绍了在ASP.NET Core中如何配置和实现基于SSL证书的方式访问MongoDB数据库,希望对你有所帮助!
参考资料
MongoDB.Driver官方文档