@warriorteam/zalo-personal
Version:
Unofficial Zalo Personal API for JavaScript - A powerful library for interacting with Zalo personal accounts with URL attachment support
467 lines (378 loc) • 12.7 kB
Markdown
# Xác Thực (Authentication)
## Tổng Quan
Zalo Personal SDK hỗ trợ hai phương thức đăng nhập chính:
- **Cookie Authentication**: Sử dụng cookie từ browser
- **QR Code Authentication**: Quét mã QR để đăng nhập
## Đăng Nhập Bằng Cookie
### 1. Lấy Cookie Từ Browser
Để sử dụng cookie authentication, bạn cần lấy cookie từ browser:
1. Mở Zalo Web (chat.zalo.me)
2. Đăng nhập vào tài khoản
3. Mở Developer Tools (F12)
4. Vào tab Application/Storage → Cookies
5. Copy tất cả cookies
### 2. Cấu Hình Credentials
```typescript
import { Zalo, Credentials } from 'zalo-personal-sdk';
const credentials: Credentials = {
imei: 'your-device-imei', // IMEI thiết bị (có thể generate)
cookie: [
{
domain: ".zalo.me",
name: "_zlang",
value: "vn",
path: "/",
// ... các thuộc tính cookie khác
}
// ... thêm các cookie khác
],
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
language: 'vi' // Optional, mặc định là 'vi'
};
```
### 3. Đăng Nhập
```typescript
const zalo = new Zalo({
selfListen: true, // Lắng nghe tin nhắn của chính mình
logLevel: 'info', // Mức độ log (info, debug, error)
apiVersion: 'v1' // Phiên bản API
});
try {
const api = await zalo.login(credentials);
console.log('Đăng nhập thành công!');
// Sử dụng API
const ownId = await api.getOwnId();
console.log('ID của bạn:', ownId);
} catch (error) {
console.error('Lỗi đăng nhập:', error.message);
}
```
### 4. Generate IMEI
```typescript
import { generateZaloUUID } from 'zalo-personal-sdk/utils';
const userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36';
const imei = generateZaloUUID(userAgent);
console.log('Generated IMEI:', imei);
```
## Đăng Nhập Bằng QR Code
### 1. Cấu Hình QR Login
```typescript
import { Zalo, LoginQRCallbackEventType } from 'zalo-personal-sdk';
const zalo = new Zalo();
const options = {
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
language: 'vi',
qrPath: './qr-code.png' // Optional: đường dẫn lưu QR code
};
```
### 2. Callback Handler
```typescript
const qrCallback = (event) => {
switch (event.type) {
case LoginQRCallbackEventType.QrCodeGenerated:
console.log('QR Code đã được tạo tại:', event.data.qrCodePath);
console.log('QR Code URL:', event.data.qrCodeUrl);
// Hiển thị QR code cho người dùng quét
break;
case LoginQRCallbackEventType.WaitingForScan:
console.log('Đang chờ quét QR code...');
break;
case LoginQRCallbackEventType.Scanned:
console.log('QR code đã được quét, đang chờ xác nhận...');
break;
case LoginQRCallbackEventType.Confirmed:
console.log('Đã xác nhận đăng nhập trên điện thoại');
break;
case LoginQRCallbackEventType.LoggedIn:
console.log('Đăng nhập thành công!');
break;
case LoginQRCallbackEventType.GotLoginInfo:
console.log('Thông tin đăng nhập:', {
cookie: event.data.cookie,
imei: event.data.imei,
userAgent: event.data.userAgent
});
// Lưu thông tin này để sử dụng cho lần đăng nhập sau
saveCredentials(event.data);
break;
case LoginQRCallbackEventType.Error:
console.error('Lỗi đăng nhập QR:', event.data.error);
break;
case LoginQRCallbackEventType.Timeout:
console.log('QR code đã hết hạn, tạo QR mới...');
break;
}
};
```
### 3. Thực Hiện QR Login
```typescript
try {
const api = await zalo.loginQR(options, qrCallback);
console.log('Đăng nhập QR thành công!');
// API đã sẵn sàng sử dụng
const ownId = await api.getOwnId();
console.log('ID của bạn:', ownId);
} catch (error) {
console.error('Lỗi đăng nhập QR:', error.message);
}
```
### 4. Lưu Trữ Credentials
```typescript
function saveCredentials(loginData) {
const credentials = {
imei: loginData.imei,
cookie: loginData.cookie,
userAgent: loginData.userAgent,
language: 'vi'
};
// Lưu vào file
fs.writeFileSync('./credentials.json', JSON.stringify(credentials, null, 2));
// Hoặc lưu vào database
// await db.saveCredentials(userId, credentials);
}
function loadCredentials() {
try {
const data = fs.readFileSync('./credentials.json', 'utf8');
return JSON.parse(data);
} catch (error) {
return null;
}
}
```
## Xử Lý Session
### 1. Kiểm Tra Session
```typescript
// Kiểm tra xem session có còn hợp lệ không
try {
const accountInfo = await api.fetchAccountInfo();
console.log('Session hợp lệ:', accountInfo);
} catch (error) {
console.log('Session hết hạn, cần đăng nhập lại');
// Thực hiện đăng nhập lại
}
```
### 2. Keep Alive
```typescript
// Giữ session active
setInterval(async () => {
try {
await api.keepAlive();
console.log('Keep alive thành công');
} catch (error) {
console.error('Keep alive thất bại:', error.message);
}
}, 5 * 60 * 1000); // 5 phút
```
### 3. Refresh Session
```typescript
async function refreshSession() {
try {
// Thử các API đơn giản để kiểm tra session
await api.getOwnId();
return true;
} catch (error) {
console.log('Session hết hạn, đăng nhập lại...');
// Đăng nhập lại bằng credentials đã lưu
const savedCredentials = loadCredentials();
if (savedCredentials) {
try {
const newApi = await zalo.login(savedCredentials);
return newApi;
} catch (loginError) {
console.error('Không thể đăng nhập lại:', loginError.message);
return false;
}
}
return false;
}
}
```
## Xử Lý Lỗi
### 1. Các Lỗi Thường Gặp
```typescript
import { ZaloApiError } from 'zalo-personal-sdk';
try {
const api = await zalo.login(credentials);
} catch (error) {
if (error instanceof ZaloApiError) {
switch (error.message) {
case 'Missing required params':
console.error('Thiếu thông tin đăng nhập bắt buộc');
break;
case 'Đăng nhập thất bại':
console.error('Cookie không hợp lệ hoặc hết hạn');
break;
case 'Khởi tạo ngữ cảnh thất bại':
console.error('Lỗi khởi tạo session');
break;
default:
console.error('Lỗi không xác định:', error.message);
}
} else {
console.error('Lỗi hệ thống:', error);
}
}
```
### 2. Retry Logic
```typescript
async function loginWithRetry(credentials, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
console.log(`Thử đăng nhập lần ${attempt}...`);
const api = await zalo.login(credentials);
console.log('Đăng nhập thành công!');
return api;
} catch (error) {
console.error(`Lần thử ${attempt} thất bại:`, error.message);
if (attempt === maxRetries) {
throw new Error(`Đăng nhập thất bại sau ${maxRetries} lần thử`);
}
// Chờ trước khi thử lại
await new Promise(resolve => setTimeout(resolve, 2000 * attempt));
}
}
}
```
## Bảo Mật
### 1. Bảo Vệ Credentials
```typescript
// KHÔNG hard-code credentials trong code
// ✗ Sai
const credentials = {
cookie: [{ name: 'session', value: 'abc123...' }]
};
// ✓ Đúng
const credentials = {
cookie: JSON.parse(process.env.ZALO_COOKIES),
imei: process.env.ZALO_IMEI,
userAgent: process.env.ZALO_USER_AGENT
};
```
### 2. Mã Hóa Credentials
```typescript
const crypto = require('crypto');
function encryptCredentials(credentials, secretKey) {
const cipher = crypto.createCipher('aes-256-cbc', secretKey);
let encrypted = cipher.update(JSON.stringify(credentials), 'utf8', 'hex');
encrypted += cipher.final('hex');
return encrypted;
}
function decryptCredentials(encryptedData, secretKey) {
const decipher = crypto.createDecipher('aes-256-cbc', secretKey);
let decrypted = decipher.update(encryptedData, 'hex', 'utf8');
decrypted += decipher.final('utf8');
return JSON.parse(decrypted);
}
```
### 3. Validate Credentials
```typescript
function validateCredentials(credentials) {
if (!credentials.imei || typeof credentials.imei !== 'string') {
throw new Error('IMEI không hợp lệ');
}
if (!credentials.cookie || !Array.isArray(credentials.cookie)) {
throw new Error('Cookie không hợp lệ');
}
if (!credentials.userAgent || typeof credentials.userAgent !== 'string') {
throw new Error('User Agent không hợp lệ');
}
return true;
}
```
## Ví Dụ Hoàn Chỉnh
```typescript
import { Zalo, ZaloApiError } from 'zalo-personal-sdk';
import fs from 'fs/promises';
class ZaloAuth {
private zalo: Zalo;
private api: any = null;
constructor() {
this.zalo = new Zalo({
selfListen: false,
logLevel: 'info'
});
}
async loginWithCredentials(credentialsPath: string) {
try {
const credentialsData = await fs.readFile(credentialsPath, 'utf8');
const credentials = JSON.parse(credentialsData);
validateCredentials(credentials);
this.api = await this.zalo.login(credentials);
console.log('✅ Đăng nhập thành công!');
return this.api;
} catch (error) {
console.error('❌ Lỗi đăng nhập:', error.message);
throw error;
}
}
async loginWithQR(qrPath?: string) {
return new Promise((resolve, reject) => {
const options = {
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
language: 'vi',
qrPath: qrPath || './qr-login.png'
};
this.zalo.loginQR(options, (event) => {
switch (event.type) {
case 'qr_code_generated':
console.log('📱 Vui lòng quét QR code tại:', event.data.qrCodePath);
break;
case 'logged_in':
console.log('✅ Đăng nhập QR thành công!');
resolve(event.api);
break;
case 'got_login_info':
// Lưu credentials để lần sau sử dụng
this.saveCredentials(event.data);
break;
case 'error':
reject(new Error(event.data.error));
break;
}
}).then(api => {
this.api = api;
}).catch(reject);
});
}
private async saveCredentials(loginData: any) {
const credentials = {
imei: loginData.imei,
cookie: loginData.cookie,
userAgent: loginData.userAgent,
language: 'vi',
savedAt: new Date().toISOString()
};
await fs.writeFile('./credentials.json', JSON.stringify(credentials, null, 2));
console.log('💾 Đã lưu credentials');
}
getApi() {
if (!this.api) {
throw new Error('Chưa đăng nhập. Vui lòng gọi login trước.');
}
return this.api;
}
}
// Sử dụng
async function main() {
const auth = new ZaloAuth();
try {
// Thử đăng nhập bằng credentials đã lưu
await auth.loginWithCredentials('./credentials.json');
} catch (error) {
console.log('Không thể đăng nhập bằng credentials, sử dụng QR...');
await auth.loginWithQR();
}
const api = auth.getApi();
// Test API
const ownId = await api.getOwnId();
console.log('🆔 ID của bạn:', ownId);
}
main().catch(console.error);
```
## Lưu Ý Quan Trọng
1. **Cookie Expiry**: Cookie có thể hết hạn, cần xử lý đăng nhập lại
2. **Rate Limiting**: Không đăng nhập quá nhiều lần trong thời gian ngắn
3. **User Agent**: Sử dụng User Agent thật, không fake
4. **Security**: Không chia sẻ credentials với người khác
5. **Backup**: Luôn backup credentials ở nơi an toàn
6. **Environment**: Sử dụng environment variables cho production