Security: 移除硬編碼的資料庫帳密
- database.py: 改從環境變數讀取 DB 設定,新增必要變數檢查 - settings.py: 改從環境變數讀取 DB 設定 - test_db_connection.py: 改從環境變數讀取 DB 設定 所有機敏資料現在必須透過 .env 檔案設定, 參考 .env.example 取得設定範本。 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -204,29 +204,60 @@ def get_database_manager() -> DatabaseManager:
|
|||||||
優先順序:
|
優先順序:
|
||||||
1. 環境變數
|
1. 環境變數
|
||||||
2. Scrapy settings(如果可用)
|
2. Scrapy settings(如果可用)
|
||||||
3. 預設值
|
|
||||||
|
環境變數:
|
||||||
|
DB_HOST: 資料庫主機位址 (必要)
|
||||||
|
DB_PORT: 資料庫埠號 (預設: 3306)
|
||||||
|
DB_USER: 資料庫使用者名稱 (必要)
|
||||||
|
DB_PASSWORD: 資料庫密碼 (必要)
|
||||||
|
DB_NAME: 資料庫名稱 (必要)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
DatabaseManager: 資料庫管理物件
|
DatabaseManager: 資料庫管理物件
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: 當必要的環境變數未設定時
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
# 載入 .env 檔案
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
# 嘗試從 Scrapy settings 取得設定
|
# 嘗試從 Scrapy settings 取得設定
|
||||||
try:
|
try:
|
||||||
from scrapy.utils.project import get_project_settings
|
from scrapy.utils.project import get_project_settings
|
||||||
settings = get_project_settings()
|
settings = get_project_settings()
|
||||||
host = settings.get('DB_HOST', os.environ.get('DB_HOST', 'mysql.theaken.com'))
|
host = settings.get('DB_HOST') or os.environ.get('DB_HOST')
|
||||||
port = settings.getint('DB_PORT', int(os.environ.get('DB_PORT', 33306)))
|
port = settings.getint('DB_PORT', int(os.environ.get('DB_PORT', 3306)))
|
||||||
user = settings.get('DB_USER', os.environ.get('DB_USER', 'A101'))
|
user = settings.get('DB_USER') or os.environ.get('DB_USER')
|
||||||
password = settings.get('DB_PASSWORD', os.environ.get('DB_PASSWORD', 'Aa123456'))
|
password = settings.get('DB_PASSWORD') or os.environ.get('DB_PASSWORD')
|
||||||
database = settings.get('DB_NAME', os.environ.get('DB_NAME', 'db_A101'))
|
database = settings.get('DB_NAME') or os.environ.get('DB_NAME')
|
||||||
except:
|
except:
|
||||||
# 如果無法取得 Scrapy settings,使用環境變數或預設值
|
# 如果無法取得 Scrapy settings,使用環境變數
|
||||||
host = os.environ.get('DB_HOST', 'mysql.theaken.com')
|
host = os.environ.get('DB_HOST')
|
||||||
port = int(os.environ.get('DB_PORT', 33306))
|
port = int(os.environ.get('DB_PORT', 3306))
|
||||||
user = os.environ.get('DB_USER', 'A101')
|
user = os.environ.get('DB_USER')
|
||||||
password = os.environ.get('DB_PASSWORD', 'Aa123456')
|
password = os.environ.get('DB_PASSWORD')
|
||||||
database = os.environ.get('DB_NAME', 'db_A101')
|
database = os.environ.get('DB_NAME')
|
||||||
|
|
||||||
|
# 檢查必要的設定
|
||||||
|
missing_vars = []
|
||||||
|
if not host:
|
||||||
|
missing_vars.append('DB_HOST')
|
||||||
|
if not user:
|
||||||
|
missing_vars.append('DB_USER')
|
||||||
|
if not password:
|
||||||
|
missing_vars.append('DB_PASSWORD')
|
||||||
|
if not database:
|
||||||
|
missing_vars.append('DB_NAME')
|
||||||
|
|
||||||
|
if missing_vars:
|
||||||
|
raise ValueError(
|
||||||
|
f"缺少必要的環境變數: {', '.join(missing_vars)}\n"
|
||||||
|
f"請在 .env 檔案或系統環境變數中設定這些值。\n"
|
||||||
|
f"參考 .env.example 檔案取得設定範本。"
|
||||||
|
)
|
||||||
|
|
||||||
return DatabaseManager(host, port, user, password, database)
|
return DatabaseManager(host, port, user, password, database)
|
||||||
|
|
||||||
|
|||||||
@@ -60,12 +60,16 @@ ITEM_PIPELINES = {
|
|||||||
'hbr_crawler.pipelines.DatabasePipeline': 400,
|
'hbr_crawler.pipelines.DatabasePipeline': 400,
|
||||||
}
|
}
|
||||||
|
|
||||||
# 資料庫設定
|
# 資料庫設定(從環境變數讀取)
|
||||||
DB_HOST = 'mysql.theaken.com'
|
import os
|
||||||
DB_PORT = 33306
|
from dotenv import load_dotenv
|
||||||
DB_USER = 'A101'
|
load_dotenv()
|
||||||
DB_PASSWORD = 'Aa123456'
|
|
||||||
DB_NAME = 'db_A101'
|
DB_HOST = os.environ.get('DB_HOST')
|
||||||
|
DB_PORT = int(os.environ.get('DB_PORT', 3306))
|
||||||
|
DB_USER = os.environ.get('DB_USER')
|
||||||
|
DB_PASSWORD = os.environ.get('DB_PASSWORD')
|
||||||
|
DB_NAME = os.environ.get('DB_NAME')
|
||||||
|
|
||||||
# Enable and configure the AutoThrottle extension (disabled by default)
|
# Enable and configure the AutoThrottle extension (disabled by default)
|
||||||
# See https://docs.scrapy.org/en/latest/topics/autothrottle.html
|
# See https://docs.scrapy.org/en/latest/topics/autothrottle.html
|
||||||
|
|||||||
@@ -20,17 +20,28 @@ logger = logging.getLogger(__name__)
|
|||||||
project_root = Path(__file__).parent
|
project_root = Path(__file__).parent
|
||||||
sys.path.insert(0, str(project_root))
|
sys.path.insert(0, str(project_root))
|
||||||
|
|
||||||
|
from dotenv import load_dotenv
|
||||||
from hbr_crawler.hbr_crawler.database import DatabaseManager, get_database_manager
|
from hbr_crawler.hbr_crawler.database import DatabaseManager, get_database_manager
|
||||||
|
|
||||||
# 資料庫連線資訊
|
# 載入 .env 檔案
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
# 資料庫連線資訊(從環境變數讀取)
|
||||||
DB_CONFIG = {
|
DB_CONFIG = {
|
||||||
'host': 'mysql.theaken.com',
|
'host': os.environ.get('DB_HOST'),
|
||||||
'port': 33306,
|
'port': int(os.environ.get('DB_PORT', 3306)),
|
||||||
'user': 'A101',
|
'user': os.environ.get('DB_USER'),
|
||||||
'password': 'Aa123456',
|
'password': os.environ.get('DB_PASSWORD'),
|
||||||
'database': 'db_A101'
|
'database': os.environ.get('DB_NAME')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# 檢查必要的環境變數
|
||||||
|
missing_vars = [k for k, v in DB_CONFIG.items() if v is None and k != 'port']
|
||||||
|
if missing_vars:
|
||||||
|
print(f"錯誤: 缺少必要的環境變數: {', '.join(['DB_' + k.upper() for k in missing_vars])}")
|
||||||
|
print("請在 .env 檔案中設定這些值,參考 .env.example")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
def test_basic_connection():
|
def test_basic_connection():
|
||||||
"""測試基本連線(不指定資料庫)"""
|
"""測試基本連線(不指定資料庫)"""
|
||||||
@@ -57,7 +68,7 @@ def test_basic_connection():
|
|||||||
def create_database():
|
def create_database():
|
||||||
"""建立 HBR_scraper 資料庫(如果需要)"""
|
"""建立 HBR_scraper 資料庫(如果需要)"""
|
||||||
print("\n" + "="*50)
|
print("\n" + "="*50)
|
||||||
print("測試 2: 檢查資料庫連線(使用現有資料庫 db_A101)")
|
print("測試 2: 檢查資料庫連線(使用現有資料庫)")
|
||||||
print("="*50)
|
print("="*50)
|
||||||
|
|
||||||
db_manager = DatabaseManager(
|
db_manager = DatabaseManager(
|
||||||
@@ -85,9 +96,9 @@ def create_database():
|
|||||||
|
|
||||||
|
|
||||||
def test_database_connection():
|
def test_database_connection():
|
||||||
"""測試連接到 db_A101 資料庫"""
|
"""測試連接到指定資料庫"""
|
||||||
print("\n" + "="*50)
|
print("\n" + "="*50)
|
||||||
print("測試 3: 連接到 db_A101 資料庫")
|
print(f"測試 3: 連接到 {DB_CONFIG['database']} 資料庫")
|
||||||
print("="*50)
|
print("="*50)
|
||||||
|
|
||||||
db_manager = DatabaseManager(
|
db_manager = DatabaseManager(
|
||||||
@@ -209,4 +220,3 @@ def main():
|
|||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
sys.exit(main())
|
sys.exit(main())
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user