495 lines
11 KiB
Markdown
495 lines
11 KiB
Markdown
---
|
||
name: 存储与认证
|
||
description: 管理 Cookie、localStorage、sessionStorage、浏览器存储状态,保存与恢复认证,或测试依赖存储的功能
|
||
metadata:
|
||
type: reference
|
||
---
|
||
|
||
# 存储与认证
|
||
|
||
> **使用场景**:管理 Cookie、localStorage、sessionStorage、浏览器存储状态,保存与恢复认证,或测试依赖存储的功能。
|
||
> **前置条件**:[core-commands.md](core-commands.md)——了解基本 CLI 用法
|
||
|
||
## 快速参考
|
||
|
||
```bash
|
||
# 将所有浏览器状态(Cookie + localStorage)保存到文件
|
||
playwright-cli state-save auth.json
|
||
|
||
# 在新会话中恢复状态
|
||
playwright-cli state-load auth.json
|
||
|
||
# 快速 Cookie 操作
|
||
playwright-cli cookie-list
|
||
playwright-cli cookie-set session_id abc123 --domain=example.com --httpOnly --secure
|
||
playwright-cli cookie-delete session_id
|
||
playwright-cli cookie-clear
|
||
|
||
# localStorage
|
||
playwright-cli localstorage-set theme dark
|
||
playwright-cli localstorage-get theme
|
||
playwright-cli localstorage-clear
|
||
|
||
# sessionStorage
|
||
playwright-cli sessionstorage-set step 3
|
||
playwright-cli sessionstorage-get step
|
||
playwright-cli sessionstorage-clear
|
||
```
|
||
|
||
## 存储状态(保存与恢复)
|
||
|
||
最强大的功能——将整个浏览器状态(所有来源的 Cookie + localStorage)保存到一个 JSON 文件中,之后恢复该状态以跳过登录流程。
|
||
|
||
### 保存存储状态
|
||
|
||
```bash
|
||
# 保存到自动生成的文件名(storage-state-{timestamp}.json)
|
||
playwright-cli state-save
|
||
|
||
# 保存到指定文件
|
||
playwright-cli state-save auth.json
|
||
playwright-cli state-save ./states/admin-session.json
|
||
```
|
||
|
||
### 恢复存储状态
|
||
|
||
```bash
|
||
# 从文件加载状态
|
||
playwright-cli state-load auth.json
|
||
|
||
# 加载后导航——Cookie 和 localStorage 已设置好
|
||
playwright-cli goto https://app.example.com/dashboard
|
||
# 已通过认证!
|
||
```
|
||
|
||
### 存储状态文件格式
|
||
|
||
保存的 JSON 同时包含 Cookie 和 localStorage:
|
||
|
||
```json
|
||
{
|
||
"cookies": [
|
||
{
|
||
"name": "session_id",
|
||
"value": "abc123",
|
||
"domain": "example.com",
|
||
"path": "/",
|
||
"expires": 1735689600,
|
||
"httpOnly": true,
|
||
"secure": true,
|
||
"sameSite": "Lax"
|
||
}
|
||
],
|
||
"origins": [
|
||
{
|
||
"origin": "https://example.com",
|
||
"localStorage": [
|
||
{ "name": "theme", "value": "dark" },
|
||
{ "name": "user_id", "value": "12345" },
|
||
{ "name": "auth_token", "value": "jwt.token.here" }
|
||
]
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
## 认证模式
|
||
|
||
最常用的工作流程——登录一次,保存状态,跨会话复用。
|
||
|
||
### 步骤 1:登录并保存
|
||
|
||
```bash
|
||
playwright-cli open https://app.example.com/login
|
||
playwright-cli snapshot
|
||
|
||
playwright-cli fill e1 "admin@example.com"
|
||
playwright-cli fill e2 "secure-password"
|
||
playwright-cli click e3
|
||
|
||
# 等待重定向以确认登录成功
|
||
playwright-cli run-code "async page => {
|
||
await page.waitForURL('**/dashboard');
|
||
return 'Login successful: ' + page.url();
|
||
}"
|
||
|
||
# 保存已认证的状态
|
||
playwright-cli state-save auth.json
|
||
playwright-cli close
|
||
```
|
||
|
||
### 步骤 2:复用认证状态
|
||
|
||
```bash
|
||
# 新会话——完全跳过登录
|
||
playwright-cli open https://app.example.com
|
||
playwright-cli state-load auth.json
|
||
playwright-cli goto https://app.example.com/dashboard
|
||
# 已以管理员身份登录!
|
||
|
||
playwright-cli snapshot # 查看仪表盘
|
||
```
|
||
|
||
### 多角色认证
|
||
|
||
```bash
|
||
# 为每个角色保存状态
|
||
playwright-cli open https://app.example.com/login
|
||
playwright-cli fill e1 "admin@example.com"
|
||
playwright-cli fill e2 "admin-pass"
|
||
playwright-cli click e3
|
||
playwright-cli state-save admin-auth.json
|
||
playwright-cli close
|
||
|
||
playwright-cli open https://app.example.com/login
|
||
playwright-cli fill e1 "user@example.com"
|
||
playwright-cli fill e2 "user-pass"
|
||
playwright-cli click e3
|
||
playwright-cli state-save user-auth.json
|
||
playwright-cli close
|
||
|
||
# 现在使用它们
|
||
playwright-cli -s=admin open https://app.example.com
|
||
playwright-cli -s=admin state-load admin-auth.json
|
||
playwright-cli -s=admin goto https://app.example.com/admin
|
||
|
||
playwright-cli -s=user open https://app.example.com
|
||
playwright-cli -s=user state-load user-auth.json
|
||
playwright-cli -s=user goto https://app.example.com/profile
|
||
```
|
||
|
||
### OAuth / SSO 认证
|
||
|
||
针对涉及重定向和弹出窗口的 OAuth 流程:
|
||
|
||
```bash
|
||
playwright-cli run-code "async page => {
|
||
await page.goto('https://app.example.com/login');
|
||
|
||
// 点击"使用 Google 登录"
|
||
const [popup] = await Promise.all([
|
||
page.waitForEvent('popup'),
|
||
page.click('button:text(\"Login with Google\")')
|
||
]);
|
||
|
||
// 在弹出窗口中填写凭据
|
||
await popup.fill('input[type=email]', 'user@gmail.com');
|
||
await popup.click('#identifierNext');
|
||
await popup.fill('input[type=password]', 'password');
|
||
await popup.click('#passwordNext');
|
||
|
||
// 等待弹出窗口关闭且主页面完成重定向
|
||
await popup.waitForEvent('close');
|
||
await page.waitForURL('**/dashboard');
|
||
|
||
// 保存已认证状态
|
||
await page.context().storageState({ path: 'oauth-auth.json' });
|
||
return 'OAuth login complete';
|
||
}"
|
||
```
|
||
|
||
## Cookies
|
||
|
||
### 列出所有 Cookie
|
||
|
||
```bash
|
||
playwright-cli cookie-list
|
||
```
|
||
|
||
### 按域名筛选
|
||
|
||
```bash
|
||
playwright-cli cookie-list --domain=example.com
|
||
```
|
||
|
||
### 按路径筛选
|
||
|
||
```bash
|
||
playwright-cli cookie-list --path=/api
|
||
```
|
||
|
||
### 获取指定 Cookie
|
||
|
||
```bash
|
||
playwright-cli cookie-get session_id
|
||
playwright-cli cookie-get __cf_bm
|
||
```
|
||
|
||
### 设置 Cookie
|
||
|
||
```bash
|
||
# 基础 Cookie
|
||
playwright-cli cookie-set session abc123
|
||
|
||
# 带完整选项的 Cookie
|
||
playwright-cli cookie-set session abc123 \
|
||
--domain=example.com \
|
||
--path=/ \
|
||
--httpOnly \
|
||
--secure \
|
||
--sameSite=Lax
|
||
|
||
# 带过期时间的 Cookie(Unix 时间戳)
|
||
playwright-cli cookie-set remember_me token123 --expires=1735689600
|
||
```
|
||
|
||
### 删除 Cookie
|
||
|
||
```bash
|
||
playwright-cli cookie-delete session_id
|
||
playwright-cli cookie-delete __cf_bm
|
||
```
|
||
|
||
### 清除所有 Cookie
|
||
|
||
```bash
|
||
playwright-cli cookie-clear
|
||
```
|
||
|
||
### 高级:一次设置多个 Cookie
|
||
|
||
```bash
|
||
playwright-cli run-code "async page => {
|
||
await page.context().addCookies([
|
||
{
|
||
name: 'session_id',
|
||
value: 'sess_abc123',
|
||
domain: 'example.com',
|
||
path: '/',
|
||
httpOnly: true,
|
||
secure: true,
|
||
sameSite: 'Strict'
|
||
},
|
||
{
|
||
name: 'preferences',
|
||
value: JSON.stringify({ theme: 'dark', lang: 'en' }),
|
||
domain: 'example.com',
|
||
path: '/'
|
||
},
|
||
{
|
||
name: 'tracking_opt_out',
|
||
value: 'true',
|
||
domain: '.example.com',
|
||
path: '/'
|
||
}
|
||
]);
|
||
}"
|
||
```
|
||
|
||
### 高级:编程方式读取所有 Cookie
|
||
|
||
```bash
|
||
playwright-cli run-code "async page => {
|
||
const cookies = await page.context().cookies();
|
||
return cookies.map(c => ({
|
||
name: c.name,
|
||
value: c.value.substring(0, 20) + '...',
|
||
domain: c.domain,
|
||
httpOnly: c.httpOnly,
|
||
secure: c.secure,
|
||
expires: new Date(c.expires * 1000).toISOString()
|
||
}));
|
||
}"
|
||
```
|
||
|
||
## Local Storage
|
||
|
||
### 列出所有项目
|
||
|
||
```bash
|
||
playwright-cli localstorage-list
|
||
```
|
||
|
||
### 获取值
|
||
|
||
```bash
|
||
playwright-cli localstorage-get theme
|
||
playwright-cli localstorage-get auth_token
|
||
```
|
||
|
||
### 设置值
|
||
|
||
```bash
|
||
playwright-cli localstorage-set theme dark
|
||
playwright-cli localstorage-set language en-US
|
||
|
||
# 设置 JSON 值(对 JSON 加引号)
|
||
playwright-cli localstorage-set user_settings '{"theme":"dark","fontSize":14,"sidebar":true}'
|
||
```
|
||
|
||
### 删除项目
|
||
|
||
```bash
|
||
playwright-cli localstorage-delete auth_token
|
||
```
|
||
|
||
### 清除所有
|
||
|
||
```bash
|
||
playwright-cli localstorage-clear
|
||
```
|
||
|
||
### 高级:批量操作
|
||
|
||
```bash
|
||
playwright-cli run-code "async page => {
|
||
await page.evaluate(() => {
|
||
localStorage.setItem('token', 'jwt_abc123');
|
||
localStorage.setItem('user_id', '12345');
|
||
localStorage.setItem('user_name', 'Jane Doe');
|
||
localStorage.setItem('preferences', JSON.stringify({
|
||
theme: 'dark',
|
||
notifications: true,
|
||
language: 'en'
|
||
}));
|
||
localStorage.setItem('onboarding_complete', 'true');
|
||
});
|
||
}"
|
||
```
|
||
|
||
### 高级:读取所有 localStorage
|
||
|
||
```bash
|
||
playwright-cli run-code "async page => {
|
||
return await page.evaluate(() => {
|
||
const items = {};
|
||
for (let i = 0; i < localStorage.length; i++) {
|
||
const key = localStorage.key(i);
|
||
items[key] = localStorage.getItem(key);
|
||
}
|
||
return items;
|
||
});
|
||
}"
|
||
```
|
||
|
||
## Session Storage
|
||
|
||
Session storage 按标签页隔离,关闭标签页时自动清除。
|
||
|
||
### 列出所有项目
|
||
|
||
```bash
|
||
playwright-cli sessionstorage-list
|
||
```
|
||
|
||
### 获取 / 设置 / 删除
|
||
|
||
```bash
|
||
playwright-cli sessionstorage-get form_step
|
||
playwright-cli sessionstorage-set form_step 3
|
||
playwright-cli sessionstorage-set form_data '{"name":"Jane","email":"jane@example.com"}'
|
||
playwright-cli sessionstorage-delete form_step
|
||
playwright-cli sessionstorage-clear
|
||
```
|
||
|
||
## IndexedDB
|
||
|
||
IndexedDB 需要通过 `run-code` 进行访问:
|
||
|
||
### 列出数据库
|
||
|
||
```bash
|
||
playwright-cli run-code "async page => {
|
||
return await page.evaluate(async () => {
|
||
const databases = await indexedDB.databases();
|
||
return databases.map(db => ({ name: db.name, version: db.version }));
|
||
});
|
||
}"
|
||
```
|
||
|
||
### 删除数据库
|
||
|
||
```bash
|
||
playwright-cli run-code "async page => {
|
||
await page.evaluate(dbName => {
|
||
indexedDB.deleteDatabase(dbName);
|
||
}, 'myDatabase');
|
||
return 'Database deleted';
|
||
}"
|
||
```
|
||
|
||
### 从对象存储中读取数据
|
||
|
||
```bash
|
||
playwright-cli run-code "async page => {
|
||
return await page.evaluate(() => {
|
||
return new Promise((resolve, reject) => {
|
||
const request = indexedDB.open('myDatabase');
|
||
request.onsuccess = () => {
|
||
const db = request.result;
|
||
const tx = db.transaction('myStore', 'readonly');
|
||
const store = tx.objectStore('myStore');
|
||
const getAll = store.getAll();
|
||
getAll.onsuccess = () => resolve(getAll.result);
|
||
getAll.onerror = () => reject(getAll.error);
|
||
};
|
||
request.onerror = () => reject(request.error);
|
||
});
|
||
});
|
||
}"
|
||
```
|
||
|
||
## 常见模式
|
||
|
||
### Token 刷新测试
|
||
|
||
```bash
|
||
# 设置一个已过期的 Token 以测试刷新逻辑
|
||
playwright-cli localstorage-set auth_token "expired-jwt-token"
|
||
playwright-cli localstorage-set token_expiry "1609459200"
|
||
|
||
# 导航以触发 Token 刷新
|
||
playwright-cli goto https://app.example.com/dashboard
|
||
|
||
# 检查 Token 是否已刷新
|
||
playwright-cli localstorage-get auth_token
|
||
```
|
||
|
||
### 功能开关测试
|
||
|
||
```bash
|
||
# 通过 localStorage 启用功能开关
|
||
playwright-cli localstorage-set feature_flags '{"newCheckout":true,"darkMode":true,"betaFeatures":false}'
|
||
|
||
# 重新加载以生效
|
||
playwright-cli reload
|
||
playwright-cli snapshot
|
||
```
|
||
|
||
### 清除所有内容,从头开始
|
||
|
||
```bash
|
||
playwright-cli cookie-clear
|
||
playwright-cli localstorage-clear
|
||
playwright-cli sessionstorage-clear
|
||
playwright-cli reload
|
||
```
|
||
|
||
### 保存与恢复的完整流程
|
||
|
||
```bash
|
||
# 手动设置状态
|
||
playwright-cli open https://example.com
|
||
playwright-cli cookie-set session abc123 --domain=example.com
|
||
playwright-cli localstorage-set user john
|
||
playwright-cli localstorage-set theme dark
|
||
|
||
# 保存所有内容
|
||
playwright-cli state-save my-session.json
|
||
|
||
# 之后——在新会话中恢复状态
|
||
playwright-cli open https://example.com
|
||
playwright-cli state-load my-session.json
|
||
playwright-cli reload
|
||
# Cookie 和 localStorage 已恢复
|
||
```
|
||
|
||
## 安全注意事项
|
||
|
||
- **切勿提交认证状态文件**——将 `*.auth-state.json` 和 `auth.json` 添加到 `.gitignore`
|
||
- **使用后删除状态文件**——自动化完成后执行 `rm auth.json`
|
||
- **使用环境变量保存凭据**——绝不在脚本中硬编码密码
|
||
- **内存会话更安全**——默认会话不会持久化到磁盘,降低了暴露风险
|
||
- **轮换已保存的状态**——认证 Token 会过期;请定期重新生成状态文件
|
||
- **避免在共享机器上保存状态**——存储状态文件包含会话 Token 和个人数据
|