如何实现Kotlin CLI安全连接Heroku PostgreSQL并读取JSON数据
安全实现Kotlin CLI连接Heroku PostgreSQL的方案
核心原则:绝对避免直接暴露数据库凭证给CLI
直接把数据库连接字符串硬编码到CLI里,或者分发给用户,等于把数据库完全暴露给任何人——这是绝对不能碰的风险操作。最优方案是通过Django作为中间层代理请求,而非让CLI直接连数据库。
方案一:用Django API作为数据代理(推荐)
让CLI通过调用Django提供的API接口获取数据,由Django负责安全连接数据库并返回JSON,这是最安全的架构。
步骤1:在Django中实现安全的API接口
- 创建一个仅返回所需JSON数据的视图,加入API密钥验证(或用户登录态验证,比如JWT)
- 把API密钥存在Heroku环境变量中,不要硬编码到代码里
示例Django视图(简化版):
from django.http import JsonResponse from django.views.decorators.http import require_GET from django.views.decorators.csrf import csrf_exempt import os from .models import TargetModel # 替换成你的数据模型 @csrf_exempt @require_GET def fetch_json_data(request): # 验证请求携带的API密钥 request_api_key = request.GET.get('api_key') valid_api_key = os.environ.get('CLI_API_KEY') # 从Heroku环境变量读取 if request_api_key != valid_api_key: return JsonResponse({'error': '无权访问'}, status=401) # 查询数据库并转换为JSON格式 queryset = TargetModel.objects.values('field1', 'field2') # 只返回需要的字段 return JsonResponse(list(queryset), safe=False)
步骤2:在Kotlin CLI中调用Django API
用HTTP客户端(比如OkHttp、Ktor)发送HTTPS请求,携带合法的API密钥。不要把API密钥硬编码在CLI里,让用户通过参数或配置文件输入(比如./your-cli --api-key=xxx)。
示例Kotlin代码(使用OkHttp):
import okhttp3.OkHttpClient import okhttp3.Request fun fetchData(apiKey: String) { val client = OkHttpClient() val request = Request.Builder() .url("https://your-heroku-app.herokuapp.com/fetch-json-data/?api_key=$apiKey") .build() client.newCall(request).execute().use { response -> when { !response.isSuccessful -> throw RuntimeException("请求失败,状态码: ${response.code}") response.body == null -> throw RuntimeException("无返回数据") else -> { val jsonData = response.body.string() // 处理获取到的JSON数据 println(jsonData) } } } }
安全优化
- 给每个用户生成专属API密钥:在Django中实现用户系统,用户登录后可生成/重置自己的API密钥,便于权限管控和 revoke
- 启用API请求频率限制:用Django的
django-ratelimit等工具防止恶意请求
方案二:直接连接数据库(不推荐,仅作备选)
如果必须让CLI直接连PostgreSQL,一定要做严格的权限限制:
步骤1:创建只读数据库用户
在Heroku PostgreSQL中创建仅拥有SELECT权限的用户,避免全权限凭证泄露:
- 进入Heroku数据库终端:
heroku pg:psql - 执行SQL命令:
-- 创建只读用户 CREATE USER cli_readonly WITH PASSWORD '强随机密码'; -- 授予所有表的只读权限 GRANT SELECT ON ALL TABLES IN SCHEMA public TO cli_readonly; -- 设置默认权限,确保新表也能被读取 ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO cli_readonly;
步骤2:生成专属连接字符串
在Heroku中为这个只读用户生成独立的连接字符串:
heroku pg:credentials:create cli_readonly
把生成的连接字符串分发给用户(或让用户自行获取),不要硬编码到CLI中。
步骤3:Kotlin CLI中用JDBC连接
使用PostgreSQL JDBC驱动连接数据库,读取数据并转换为JSON:
import java.sql.DriverManager import org.postgresql.Driver import com.google.gson.GsonBuilder fun connectAndFetchData(dbUrl: String) { // 注册PostgreSQL驱动 DriverManager.registerDriver(Driver()) DriverManager.getConnection(dbUrl).use { connection -> val statement = connection.createStatement() val resultSet = statement.executeQuery("SELECT field1, field2 FROM target_table") // 把ResultSet转换为JSON val gson = GsonBuilder().create() val dataList = mutableListOf<MutableMap<String, Any?>>() while (resultSet.next()) { val row = mutableMapOf<String, Any?>() row["field1"] = resultSet.getObject("field1") row["field2"] = resultSet.getObject("field2") dataList.add(row) } println(gson.toJson(dataList)) } }
CLI分发的安全注意事项
- 绝对不要在CLI安装包或代码中嵌入任何敏感信息(API密钥、数据库凭证)
- 引导用户从你的Django网站获取合法访问凭证(比如登录后生成API密钥)
- 强制CLI使用HTTPS请求Django API,禁止HTTP传输,避免数据被窃听
内容的提问来源于stack exchange,提问作者8SIXSector
相关产品推荐
相关产品推荐

