Xác thực & Quản lý phiên làm việc
Bài học này giải thích cách hệ thống quản lý xác thực sử dụng Playwright Storage State - một cách tiếp cận đơn giản và hiệu quả.
1. Vấn đề cần giải quyết
Khi ghi/phát lại trên các trang yêu cầu đăng nhập:
| Vấn đề | Hậu quả |
|---|---|
| Phải đăng nhập mỗi lần ghi | Mất thời gian, lặp lại |
| Phiên hết hạn | Phát lại thất bại |
| Lưu tên đăng nhập/mật khẩu | Rủi ro bảo mật |
2. Giải pháp: Trạng thái lưu trữ Playwright
Playwright cung cấp cơ chế --save-storage và --load-storage để lưu/load trạng thái browser (cookies, localStorage).
2.1. Quy trình
┌─────────────────────────────────────────────────────────────┐
│ LƯU PHIÊN (1 lần) │
├─────────────────────────────────────────────────────────────┤
│ 1. Chạy: playwright codegen --save-storage=auth.json URL │
│ 2. Đăng nhập thủ công trong trình duyệt │
│ 3. Đóng trình duyệt → Phiên lưu vào auth.json │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ TẢI PHIÊN (mỗi lần) │
├─────────────────────────────────────────────────────────────┤
│ 1. Chạy: playwright codegen --load-storage=auth.json URL │
│ 2. Trình duyệt mở với phiên đã đăng nhập │
│ 3. Bắt đầu ghi/phát lại ngay │
└─────────────────────────────────────────────────────────────┘2.2. Định dạng trạng thái lưu trữ
json
{
"cookies": [
{
"name": "session_id",
"value": "abc123...",
"domain": ".example.com",
"path": "/",
"expires": 1702339200,
"httpOnly": true,
"secure": true,
"sameSite": "Lax"
}
],
"origins": [
{
"origin": "https://example.com",
"localStorage": [
{ "name": "token", "value": "xyz789..." }
]
}
]
}3. Triển khai
3.1. Trình quản lý xác thực (src/auth_manager.py)
Module đơn giản hóa, chỉ quản lý trạng thái lưu trữ:
python
def get_auth_file_path() -> Path:
"""Tìm file auth.json trong nhiều vị trí."""
search_paths = [
Path('auth.json'), # CWD
Path(__file__).parent.parent / 'auth.json', # Project root
]
# Nếu chạy từ EXE
if getattr(sys, 'frozen', False):
exe_dir = Path(sys.executable).parent
search_paths.insert(0, exe_dir / 'auth.json')
for path in search_paths:
if path.exists():
return path
return Path(__file__).parent.parent / 'auth.json'3.2. Xác thực trạng thái lưu trữ
python
def is_valid_storage_state(file_path: Path) -> bool:
"""Kiểm tra file có phải Playwright storage state hợp lệ."""
if not file_path.exists():
return False
try:
with open(file_path, 'r', encoding='utf-8') as f:
data = json.load(f)
# Playwright storage state có 'cookies' và/hoặc 'origins'
return 'cookies' in data or 'origins' in data
except (json.JSONDecodeError, IOError):
return False3.3. Lấy thông tin xác thực
python
def get_auth_info() -> dict:
"""Lấy thông tin chi tiết về auth state."""
auth_path = get_auth_file_path()
if not is_valid_storage_state(auth_path):
return {
'valid': False,
'path': str(auth_path),
'message': 'Chưa có auth state'
}
with open(auth_path, 'r', encoding='utf-8') as f:
data = json.load(f)
cookies = data.get('cookies', [])
# Extract domains từ cookies
domains = set()
for cookie in cookies:
domain = cookie.get('domain', '').lstrip('.')
domains.add(domain)
return {
'valid': True,
'path': str(auth_path),
'cookie_count': len(cookies),
'domains': list(domains),
'message': f"✅ {len(cookies)} cookies cho {len(domains)} domain(s)"
}4. Tích hợp với bộ ghi
4.1. Tải trạng thái khi ghi hình
python
# src/recorder.py
def start_recording(url: str, output_path: Path) -> bool:
"""Start recording với auth state nếu có."""
from src.auth_manager import get_auth_state_path
auth_state_path = get_auth_state_path()
# Build command
cmd = [sys.executable, "-m", "playwright", "codegen",
"--target", "python", "-o", str(output_path)]
# Thêm auth state nếu có
if auth_state_path:
cmd.extend(["--load-storage", str(auth_state_path)])
cmd.append(url)
subprocess.run(cmd, check=True)4.2. Lưu trạng thái xác thực
python
def save_auth_state(url: str, output_path: Optional[Path] = None) -> bool:
"""Mở browser để user đăng nhập và lưu session."""
if output_path is None:
output_path = get_auth_file_path()
cmd = [sys.executable, "-m", "playwright", "codegen",
"--save-storage", str(output_path), url]
print("📝 Hướng dẫn:")
print(" 1. Trình duyệt sẽ mở")
print(" 2. Đăng nhập vào trang web")
print(" 3. Đóng trình duyệt khi đăng nhập xong")
subprocess.run(cmd, check=True)
# Verify
if is_valid_storage_state(output_path):
print("✅ Đã lưu auth state thành công!")
return True
return False5. Tích hợp với bộ phát lại
5.1. Tải trạng thái vào ngữ cảnh trình duyệt
python
# src/replayer.py
def _replay_with_browser(browser, actions, images_dir, upload_enabled, upload_fn):
"""Replay với auth state."""
from src.auth_manager import get_auth_state_path, get_auth_info
auth_state_path = get_auth_state_path()
# Context options
context_options = {'viewport': {'width': 1280, 'height': 800}}
# Load auth state nếu có
if auth_state_path:
auth_info = get_auth_info()
print(f" 🔐 {auth_info.get('message', '')}")
context_options['storage_state'] = str(auth_state_path)
# Tạo context với auth
context = browser.new_context(**context_options)
page = context.new_page()
# Replay actions...6. Các lệnh CLI
6.1. Lưu xác thực
bash
python guide_ai.py --save-auth --url https://portal.inet.vnQuy trình:
- Mở trình duyệt với Playwright codegen
- Người dùng đăng nhập thủ công
- Đóng trình duyệt →
auth.jsonđược tạo
6.2. Kiểm tra trạng thái
bash
python guide_ai.py --auth-statusOutput:
🔐 AUTH STATE STATUS
--------------------------------------------------
Path: E:\automation-guide\auth.json
Status: ✅ 5 cookies cho 2 domain(s)
Domains: portal.inet.vn, sso.inet.vn6.3. Xóa xác thực
bash
python guide_ai.py --clear-auth7. So sánh với cách cũ
| Tiêu chí | Cách cũ (Tự điền form) | Cách mới (Trạng thái lưu trữ) |
|---|---|---|
| Bảo mật | Lưu tên đăng nhập/mật khẩu | Chỉ lưu token phiên |
| Độ phức tạp | Phải phát hiện form, selector | Playwright xử lý hết |
| Độ tin cậy | Phụ thuộc giao diện trang | Hoạt động với mọi trang |
| Bảo trì | Phải cập nhật khi giao diện đổi | Không cần bảo trì |
8. Thực hành tốt
8.1. Bảo mật
gitignore
# .gitignore
auth.json
*.auth.json8.2. Hết hạn token
- Token phiên có thời hạn
- Khi hết hạn → chạy lại
--save-auth - Có thể phát hiện qua phản hồi HTTP 401/403
8.3. Nhiều trang web
Hiện tại chỉ hỗ trợ 1 file auth.json. Để hỗ trợ nhiều sites:
bash
# Lưu riêng từng site
playwright codegen --save-storage=auth_portal.json https://portal.inet.vn
playwright codegen --save-storage=auth_admin.json https://admin.inet.vn
# Load theo site (future feature)
python guide_ai.py --auth-file=auth_portal.json --url https://portal.inet.vn9. Xử lý sự cố
Phiên không được tải
❌ Vấn đề: Trình duyệt mở nhưng chưa đăng nhập
✅ Giải pháp:
1. Kiểm tra auth.json tồn tại
2. Chạy --auth-status để xác minh
3. Nếu không hợp lệ, chạy lại --save-authToken hết hạn
❌ Vấn đề: Phát lại chuyển hướng về trang đăng nhập
✅ Giải pháp:
1. Xóa auth.json cũ: --clear-auth
2. Tạo mới: --save-auth --url <URL>Tổng kết
Quản lý xác thực sử dụng Trạng thái lưu trữ Playwright:
- Đơn giản: Không cần code phức tạp để phát hiện form
- An toàn: Không lưu thông tin đăng nhập, chỉ lưu phiên
- Di động: File JSON có thể sao chép giữa các máy
- Đáng tin cậy: Tính năng gốc của Playwright, hoạt động ổn định