云迈博客

您现在的位置是:首页 > 灌水专栏 > 正文

灌水专栏

使用 SSL 方式连接 MongoDB

wsinbol2023-03-21灌水专栏617
场景描述某项目使用的是云MongoDB并开启了SSL认证,着实踩了一些坑,特此记录。Shell连接华为云参考链接mongo–host–port-u-p–authent

场景描述

某项目使用的是云 MongoDB 并开启了 SSL 认证,着实踩了一些坑,特此记录。

Shell 连接

华为云参考链接

mongo –host –port -u -p –authenticationDatabase admin –ssl –sslCAFile [/root/ca.crt] –sslAllowInvalidHostnames

其中 ca.crt 为从华为云控制台下载的证书。

SpringBoot 连接

建立工程

  • AbstractMongoConfig
import lombok.Data;
import org.springframework.data.mongodb.MongoDatabaseFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoClientDatabaseFactory;

/**
 * @author SymbolWong
 * @description
 * @date 2023/3/17 20:26
 */
@Data
public abstract class AbstractMongoConfig {
    protected String host, database, username, password;
    protected int port;

    public MongoDatabaseFactory mongoDatabaseFactory() {
        String url = "mongodb://" + username + ":" + password + "@" + host + ":" + port + "/" + database + "?ssl=true";
        return new SimpleMongoClientDatabaseFactory(url);
    }

    public abstract MongoTemplate getMongoTemplate() throws Exception;
}
  • MongoSSLConfig
import com.mongodb.MongoClientSettings;
import com.mongodb.MongoCredential;
import com.mongodb.ServerAddress;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.MongoDatabaseFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoClientDatabaseFactory;

import java.util.Arrays;

@Configuration
@ConfigurationProperties(prefix = "spring.data.mongodb")
public class MongoSSLConfig extends AbstractMongoConfig {

    @Override
    @Bean
    public MongoTemplate getMongoTemplate() throws Exception {
        return new MongoTemplate(mongoDatabaseFactory());
    }

    @Override
    @Bean
    public MongoDatabaseFactory mongoDatabaseFactory() {
        MongoClient mongoClient = MongoSSLConfig.createNetworkMongoClient(host, database, username, password, port);
        return new SimpleMongoClientDatabaseFactory(mongoClient, database);
    }

    public static MongoClient createNetworkMongoClient(String host, String database, String username, String password, int port) {
        MongoCredential credential = getCredentials(username, database, password);
        MongoClientSettings settings = MongoClientSettings.builder()
                .credential(credential)
                .applyToSslSettings(builder -> {
                    builder.enabled(true); // 开启ssl连接
                    builder.invalidHostNameAllowed(true); // 禁用主机名验证
                })
                .applyToClusterSettings(builder ->
                        builder.hosts(Arrays.asList(new ServerAddress(host, port))))
                .build();
        MongoClient mongoClient = MongoClients.create(settings);
        return mongoClient;
    }

    private static MongoCredential getCredentials(String username, String database, String pass) {
        char[] password = pass.toCharArray();
        return MongoCredential.createCredential(username, database, password);
    }

}

  • MongoSSLConfig

import com.mongodb.MongoClientSettings;
import com.mongodb.MongoCredential;
import com.mongodb.ServerAddress;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.MongoDatabaseFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoClientDatabaseFactory;

import java.util.Arrays;

@Configuration
@ConfigurationProperties(prefix = "spring.data.mongodb")
public class MongoSSLConfig extends AbstractMongoConfig {

    @Override
    @Bean
    public MongoTemplate getMongoTemplate() throws Exception {
        return new MongoTemplate(mongoDatabaseFactory());
    }

    @Override
    @Bean
    public MongoDatabaseFactory mongoDatabaseFactory() {
        MongoClient mongoClient = MongoSSLConfig.createNetworkMongoClient(host, database, username, password, port);
        return new SimpleMongoClientDatabaseFactory(mongoClient, database);
    }

    public static MongoClient createNetworkMongoClient(String host, String database, String username, String password, int port) {
        MongoCredential credential = getCredentials(username, database, password);
        MongoClientSettings settings = MongoClientSettings.builder()
                .credential(credential)
                .applyToSslSettings(builder -> {
                    builder.enabled(true); // 开启ssl连接
                    builder.invalidHostNameAllowed(true); // 禁用主机名验证
                })
                .applyToClusterSettings(builder ->
                        builder.hosts(Arrays.asList(new ServerAddress(host, port))))
                .build();
        MongoClient mongoClient = MongoClients.create(settings);
        return mongoClient;
    }

    private static MongoCredential getCredentials(String username, String database, String pass) {
        char[] password = pass.toCharArray();
        return MongoCredential.createCredential(username, database, password);
    }

}
  • MongoUtils
import com.tzcpa.common.constant.HttpStatus;
import com.tzcpa.common.core.page.PageDomain;
import com.tzcpa.common.core.page.TableDataInfo;
import com.tzcpa.common.core.page.TableSupport;
import org.bson.types.ObjectId;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;

import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;

public class MongoUtils {
    public static void initSsl() throws IOException {
        String truststorePassword = "123456";
        // 
        System.setProperty("javax.net.ssl.trustStore", "/home/tz/data/java/cert/mongoca.keystore");
        System.setProperty("javax.net.ssl.trustStorePassword", truststorePassword);
    }
}
  • 启动类处调用
@EnableAsync
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
public class TzcpaApplication
{
    public static void main(String[] args) throws IOException {
        Stream.of().spliterator()
        MongoUtils.initSsl();
        SpringApplication.run(TzcpaApplication.class, args);
        System.out.println("(♥◠‿◠)ノ゙  启动成功   ლ(´ڡ`ლ)゙  \n");
    }
}

证书来源

工程创建完毕,问题来到与证书相关的两个参数。javax.net.ssl.trustStorejavax.net.ssl.trustStorePassword。后续再研究他们是干什么的,先来看怎么用。
这里需要用到前面(即shell里面的crt证书),trustStore 是利用工具生成的一个keystore文件,trustStorePassword 是生成该证书的密码。

所以先执行 keytool -importcert -trustcacerts -file ca.crt -keystore mongoca.keystore -storepass 123456,这样就会生成一个mongoca.keystore的文件。将文件路径指定到MongoUtils后启动即可成功连接。

出乎意料

本以为万事大吉,没想到连接成功入库却报错 Exception authenticating MongoCredential。搜索一波说应该是账号问题。于是进入shell模式创建数据库及用户:

我先进了 admin 数据库执行:

db.createUser({
    user:"tianzhi",
    pwd:"Tianzhi_2023",
    roles:[{role:"readWrite",db:"tzcpa"}],
    passwordDigestor:"server"
})

再进行入库操作,F**k,还是同样的错误!甚至给了 roles: [ { role: "userAdminAnyDatabase", db: "tzcpa" } ]权限还是老样子。抱着试试看的态度,我去对应的业务库执行上面的创建用户语句。

再操作入库,成功!什么玩意!!!

发表评论

评论列表

  • 这篇文章还没有收到评论,赶紧来抢沙发吧~