应用账户HarmonyOS开发小实践

举报
Jack20 发表于 2026/06/20 18:30:48 2026/06/20
【摘要】 一、小知识你打开手机上的「运动健康」App,它提示你「使用华为账号登录」——点击后,跳转到一个授权页面,确认后你就自动登录了。你不需要重新输入用户名密码,甚至不需要知道密码是什么。这背后的功臣,就是应用账户。应用账户和系统账户完全是两个维度的东西。系统账户管的是"谁在用这台设备",而应用账户管的是"谁在用这个 App"。一个系统账户下可以有多个应用账户,就像一个人可以有微信账号、淘宝账号、...

一、小知识

你打开手机上的「运动健康」App,它提示你「使用华为账号登录」——点击后,跳转到一个授权页面,确认后你就自动登录了。你不需要重新输入用户名密码,甚至不需要知道密码是什么。这背后的功臣,就是应用账户

应用账户和系统账户完全是两个维度的东西。系统账户管的是"谁在用这台设备",而应用账户管的是"谁在用这个 App"。一个系统账户下可以有多个应用账户,就像一个人可以有微信账号、淘宝账号、抖音账号一样。

但应用账户的价值远不止"记住用户名密码"。它最强大的能力是跨应用账户授权——让 App A 安全地访问 App B 的账户信息,而不需要用户重复登录。这就是 HarmonyOS 生态内"一次登录,全生态通行"的技术基础。


二、核心原理

2.1 应用账户体系架构

图片.png

flowchart TB
    subgraph 应用A["应用A(资源拥有者)"]
        A1[AppAccountManager]
        A2[账户数据存储]
        A3[OAuth令牌]
    end

    subgraph 应用B["应用B(资源请求者)"]
        B1[AppAccountManager]
        B2[授权请求]
    end

    subgraph 系统["系统服务"]
        S1[AccountManager Service]
        S2[授权管理器]
        S3[令牌管理器]
    end

    B1 -->|1.请求授权| S2
    S2 -->|2.弹出授权确认| B1
    B1 -->|3.用户确认| S2
    S2 -->|4.发放授权| S1
    S1 -->|5.返回令牌| B1
    B1 -->|6.使用令牌访问| A1
    A1 -->|7.验证令牌并返回数据| B1

    classDef primary fill:#4CAF50,stroke:#388E3C,color:#fff
    classDef warning fill:#FF9800,stroke:#F57C00,color:#fff
    classDef error fill:#F44336,stroke:#D32F2F,color:#fff
    classDef info fill:#2196F3,stroke:#1976D2,color:#fff
    classDef purple fill:#9C27B0,stroke:#7B1FA2,color:#fff

    class A1,A2,A3 primary
    class B1,B2 info
    class S1,S2,S3 purple

2.2 核心概念

概念 说明 类比
AppAccountManager 应用账户管理器,所有操作的入口 银行柜员
账户名(name) 应用内唯一标识用户的名称 银行卡号
所有者(owner) 创建该账户的应用包名 开户行
授权(Authorization) 允许其他应用访问账户信息 授权书
OAuth令牌(Token) 授权后颁发的访问凭证 临时通行证
自定义数据 与账户关联的键值对数据 账户备注信息

2.3 跨应用授权流程

跨应用授权是应用账户最核心的能力。整个流程就像你去银行办理业务——你(应用B)拿着身份证(授权请求)到柜台(系统服务),柜员确认你的身份后,给你一张临时通行证(OAuth令牌),你拿着通行证就能访问金库(应用A的数据)。

sequenceDiagram
    participant AppB as 应用B
    participant System as 系统服务
    participant User as 用户
    participant AppA as 应用A

    AppB->>System: 1. createAccountCredential(name, credentialType, credential)
    System->>System: 2. 查找目标账户(owner+name)
    System->>User: 3. 弹出授权确认对话框
    User->>System: 4. 确认授权
    System->>System: 5. 生成授权令牌
    System->>AppB: 6. 返回授权结果
    AppB->>AppA: 7. 使用令牌请求资源
    AppA->>System: 8. 验证令牌有效性
    System->>AppA: 9. 令牌有效
    AppA->>AppB: 10. 返回请求的资源

三、代码实战

3.1 应用账户的创建与管理

最基础的操作:在自己的应用中创建、查询和管理应用账户。

import { appAccount } from '@kit.BasicServicesKit';
import { BusinessError } from '@kit.BasicServicesKit';

/**
 * 应用账户管理器
 * 封装应用账户的创建、查询、更新和删除操作
 */
class AppAccountManager {
  private manager: appAccount.AppAccountManager;

  constructor() {
    this.manager = appAccount.createAppAccountManager();
  }

  /**
   * 创建一个新的应用账户
   * @param name 账户名称(应用内唯一)
   */
  async createAccount(name: string): Promise<boolean> {
    try {
      await this.manager.createAccount(name);
      console.info(`[AppAccount] 账户创建成功: ${name}`);
      return true;
    } catch (error) {
      const err = error as BusinessError;
      console.error(`[AppAccount] 创建账户失败: code=${err.code}, msg=${err.message}`);

      // 常见错误码处理
      if (err.code === 12300001) {
        console.error('[AppAccount] 账户名称已存在');
      } else if (err.code === 12300002) {
        console.error('[AppAccount] 账户名称格式不合法');
      }
      return false;
    }
  }

  /**
   * 创建账户并设置额外信息
   * @param name 账户名称
   * @param extraInfo 额外信息(JSON字符串)
   */
  async createAccountWithExtraInfo(name: string, extraInfo: string): Promise<boolean> {
    try {
      await this.manager.createAccount(name, { extraInfo: extraInfo });
      console.info(`[AppAccount] 账户创建成功(含额外信息): ${name}`);
      return true;
    } catch (error) {
      const err = error as BusinessError;
      console.error(`[AppAccount] 创建账户失败: ${err.message}`);
      return false;
    }
  }

  /**
   * 查询当前应用的所有账户
   */
  async queryAllAccounts(): Promise<appAccount.AppAccountInfo[]> {
    try {
      // 获取当前应用的包名作为owner
      const accounts = await this.manager.queryAllAccounts();
      console.info(`[AppAccount] 当前应用共有 ${accounts.length} 个账户`);

      accounts.forEach((account, index) => {
        console.info(`  账户${index + 1}: name=${account.name}, owner=${account.owner}`);
      });

      return accounts;
    } catch (error) {
      const err = error as BusinessError;
      console.error(`[AppAccount] 查询账户失败: ${err.message}`);
      return [];
    }
  }

  /**
   * 查询指定所有者应用的账户列表
   * 用于跨应用场景下查询目标应用的账户
   * @param owner 目标应用的包名
   */
  async queryAccountsByOwner(owner: string): Promise<appAccount.AppAccountInfo[]> {
    try {
      const accounts = await this.manager.getAccountsByOwner(owner);
      console.info(`[AppAccount] 应用${owner}${accounts.length} 个账户`);
      return accounts;
    } catch (error) {
      const err = error as BusinessError;
      console.error(`[AppAccount] 查询指定owner账户失败: ${err.message}`);
      return [];
    }
  }

  /**
   * 删除指定账户
   * @param name 要删除的账户名称
   */
  async removeAccount(name: string): Promise<boolean> {
    try {
      await this.manager.removeAccount(name);
      console.info(`[AppAccount] 账户已删除: ${name}`);
      return true;
    } catch (error) {
      const err = error as BusinessError;
      console.error(`[AppAccount] 删除账户失败: ${err.message}`);
      return false;
    }
  }

  /**
   * 设置账户的自定义数据
   * 自定义数据以键值对形式存储,可用于同步用户偏好等
   * @param name 账户名称
   * @param key 数据键
   * @param value 数据值
   */
  async setCustomData(name: string, key: string, value: string): Promise<boolean> {
    try {
      await this.manager.setCustomData(name, key, value);
      console.info(`[AppAccount] 自定义数据已设置: ${key}=${value}`);
      return true;
    } catch (error) {
      const err = error as BusinessError;
      console.error(`[AppAccount] 设置自定义数据失败: ${err.message}`);
      return false;
    }
  }

  /**
   * 获取账户的自定义数据
   * @param name 账户名称
   * @param key 数据键
   */
  async getCustomData(name: string, key: string): Promise<string> {
    try {
      const value = await this.manager.getCustomData(name, key);
      console.info(`[AppAccount] 自定义数据: ${key}=${value}`);
      return value;
    } catch (error) {
      const err = error as BusinessError;
      console.error(`[AppAccount] 获取自定义数据失败: ${err.message}`);
      return '';
    }
  }
}

// 使用示例:社交应用的用户管理
async function demoSocialApp() {
  const accountManager = new AppAccountManager();

  // 创建用户账户
  await accountManager.createAccountWithExtraInfo(
    'user_zhangsan',
    JSON.stringify({ nickname: '张三', avatar: 'avatar_001.png', level: 5 })
  );

  // 设置自定义数据
  await accountManager.setCustomData('user_zhangsan', 'theme', 'dark');
  await accountManager.setCustomData('user_zhangsan', 'language', 'zh-CN');

  // 读取自定义数据
  const theme = await accountManager.getCustomData('user_zhangsan', 'theme');
  console.info(`[Demo] 用户主题偏好: ${theme}`);

  // 查询所有账户
  await accountManager.queryAllAccounts();
}

3.2 跨应用账户授权

这是应用账户最核心的能力——让一个应用安全地访问另一个应用的账户信息。

import { appAccount } from '@kit.BasicServicesKit';
import { BusinessError } from '@kit.BasicServicesKit';

/**
 * 跨应用授权管理器
 * 处理应用间的账户授权与令牌管理
 */
class CrossAppAuthManager {
  private manager: appAccount.AppAccountManager;

  constructor() {
    this.manager = appAccount.createAppAccountManager();
  }

  /**
   * 【授权方】设置账户的授权列表
   * 指定哪些应用可以访问本应用的账户
   * @param name 账户名称
   * @param authType 授权类型(如"OAuth2")
   * @param authorizedAppList 被授权的应用包名列表
   */
  async setAuthorizedApps(name: string, authType: string, authorizedAppList: string[]): Promise<boolean> {
    try {
      for (const app of authorizedAppList) {
        await this.manager.setAppAccess(name, app, true);
        console.info(`[CrossAuth] 已授权应用 ${app} 访问账户 ${name}`);
      }
      return true;
    } catch (error) {
      const err = error as BusinessError;
      console.error(`[CrossAuth] 设置授权失败: ${err.message}`);
      return false;
    }
  }

  /**
   * 【授权方】创建OAuth令牌
   * 为已授权的应用颁发访问令牌
   * @param name 账户名称
   * @param authType 授权类型
   * @param token 令牌内容
   */
  async createOAuthToken(name: string, authType: string, token: string): Promise<boolean> {
    try {
      await this.manager.createAccountCredential(name, authType, token);
      console.info(`[CrossAuth] OAuth令牌创建成功: account=${name}, type=${authType}`);
      return true;
    } catch (error) {
      const err = error as BusinessError;
      console.error(`[CrossAuth] 创建令牌失败: ${err.message}`);
      return false;
    }
  }

  /**
   * 【请求方】请求获取目标应用的账户授权
   * @param name 目标账户名称
   * @param owner 目标应用包名
   * @param authType 授权类型
   */
  async requestAuthorization(name: string, owner: string, authType: string): Promise<string> {
    try {
      // 发起授权请求,系统会弹出授权确认对话框
      const authResult = await this.manager.getAuthorizerInterface(name, owner, authType);
      console.info(`[CrossAuth] 授权请求已发送: account=${name}, owner=${owner}`);

      // 获取授权令牌
      const token = await this.manager.getAccountCredential(name, owner, authType);
      console.info(`[CrossAuth] 获取到授权令牌`);
      return token;
    } catch (error) {
      const err = error as BusinessError;
      console.error(`[CrossAuth] 请求授权失败: code=${err.code}, msg=${err.message}`);

      if (err.code === 12300001) {
        console.error('[CrossAuth] 目标账户不存在');
      } else if (err.code === 12300004) {
        console.error('[CrossAuth] 用户拒绝授权');
      }
      return '';
    }
  }

  /**
   * 【请求方】检查是否已获得授权
   * @param name 目标账户名称
   * @param owner 目标应用包名
   */
  async checkAuthorization(name: string, owner: string): Promise<boolean> {
    try {
      // 尝试获取账户信息来验证授权状态
      const accountInfo = await this.manager.getAccountInfo(owner, name);
      return accountInfo !== null;
    } catch {
      return false;
    }
  }

  /**
   * 【授权方】撤销对指定应用的授权
   * @param name 账户名称
   * @param app 要撤销授权的应用包名
   */
  async revokeAuthorization(name: string, app: string): Promise<boolean> {
    try {
      await this.manager.setAppAccess(name, app, false);
      console.info(`[CrossAuth] 已撤销应用 ${app} 的授权`);
      return true;
    } catch (error) {
      const err = error as BusinessError;
      console.error(`[CrossAuth] 撤销授权失败: ${err.message}`);
      return false;
    }
  }
}

// 使用示例:华为账号登录第三方应用
async function demoHuaweiAccountLogin() {
  const authManager = new CrossAppAuthManager();

  // ===== 华为账号App(授权方)的操作 =====
  // 设置授权:允许"运动健康"和"应用市场"访问华为账号
  await authManager.setAuthorizedApps(
    'huawei_user_001',
    'OAuth2',
    ['com.example.health', 'com.example.appmarket']
  );

  // 为已授权的应用创建OAuth令牌
  await authManager.createOAuthToken(
    'huawei_user_001',
    'OAuth2',
    'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...'
  );

  // ===== 运动健康App(请求方)的操作 =====
  // 请求华为账号的授权
  const token = await authManager.requestAuthorization(
    'huawei_user_001',
    'com.huawei.hwid',
    'OAuth2'
  );

  if (token) {
    console.info('[Demo] 登录成功,获取到访问令牌');
  }
}

3.3 账户数据同步

应用账户支持自定义数据的存储和跨设备同步,这对于多端协同场景至关重要。

import { appAccount } from '@kit.BasicServicesKit';
import { BusinessError } from '@kit.BasicServicesKit';

/**
 * 账户数据同步管理器
 * 管理应用账户的配置数据和同步状态
 */
class AccountSyncManager {
  private manager: appAccount.AppAccountManager;

  constructor() {
    this.manager = appAccount.createAppAccountManager();
  }

  /**
   * 保存用户配置到账户数据
   * 这些数据会随账户在设备间同步
   * @param accountName 账户名称
   * @param config 用户配置对象
   */
  async saveUserConfig(accountName: string, config: Record<string, string>): Promise<boolean> {
    try {
      // 逐个设置自定义数据
      const entries = Object.entries(config);
      for (const [key, value] of entries) {
        await this.manager.setCustomData(accountName, key, value);
      }
      console.info(`[AccountSync] 用户配置已保存,共 ${entries.length}`);
      return true;
    } catch (error) {
      const err = error as BusinessError;
      console.error(`[AccountSync] 保存配置失败: ${err.message}`);
      return false;
    }
  }

  /**
   * 加载用户配置
   * @param accountName 账户名称
   * @param keys 需要加载的配置键列表
   */
  async loadUserConfig(accountName: string, keys: string[]): Promise<Record<string, string>> {
    const config: Record<string, string> = {};

    try {
      for (const key of keys) {
        try {
          const value = await this.manager.getCustomData(accountName, key);
          if (value) {
            config[key] = value;
          }
        } catch {
          // 某个键不存在不影响其他键的加载
          console.warn(`[AccountSync] 配置键"${key}"不存在`);
        }
      }
      console.info(`[AccountSync] 已加载 ${Object.keys(config).length} 项配置`);
      return config;
    } catch (error) {
      const err = error as BusinessError;
      console.error(`[AccountSync] 加载配置失败: ${err.message}`);
      return {};
    }
  }

  /**
   * 同步账户数据到关联设备
   * 通过设置关联数据来触发同步机制
   * @param accountName 账户名称
   * @param syncData 需要同步的数据
   */
  async syncAccountData(accountName: string, syncData: appAccount.CustomData): Promise<boolean> {
    try {
      // 设置关联数据,系统会自动处理跨设备同步
      await this.manager.setCustomData(accountName, 'sync_timestamp', Date.now().toString());
      await this.manager.setCustomData(accountName, 'sync_data', JSON.stringify(syncData));

      console.info(`[AccountSync] 数据同步已触发: account=${accountName}`);
      return true;
    } catch (error) {
      const err = error as BusinessError;
      console.error(`[AccountSync] 数据同步失败: ${err.message}`);
      return false;
    }
  }

  /**
   * 监听账户数据变化
   * 当其他设备修改了账户数据,本地会收到通知
   * @param owner 账户所有者包名
   * @param name 账户名称
   * @param callback 数据变化回调
   */
  onAccountDataChange(
    owner: string,
    name: string,
    callback: (accountInfo: appAccount.AppAccountInfo) => void
  ): void {
    try {
      this.manager.on('accountChange', [name], (accounts: appAccount.AppAccountInfo[]) => {
        console.info(`[AccountSync] 收到账户数据变化通知,共 ${accounts.length} 个账户`);
        accounts.forEach(account => {
          if (account.name === name) {
            callback(account);
          }
        });
      });
      console.info(`[AccountSync] 已注册数据变化监听: ${name}`);
    } catch (error) {
      const err = error as BusinessError;
      console.error(`[AccountSync] 注册监听失败: ${err.message}`);
    }
  }

  /**
   * 取消数据变化监听
   */
  offAccountDataChange(): void {
    try {
      this.manager.off('accountChange');
      console.info('[AccountSync] 已取消数据变化监听');
    } catch (error) {
      const err = error as BusinessError;
      console.error(`[AccountSync] 取消监听失败: ${err.message}`);
    }
  }
}

// 使用示例:笔记应用的多端同步
async function demoNoteAppSync() {
  const syncManager = new AccountSyncManager();

  // 在手机端保存用户配置
  await syncManager.saveUserConfig('note_user_001', {
    'theme': 'dark',
    'font_size': '16',
    'sort_order': 'modified_time',
    'auto_sync': 'true',
  });

  // 在平板端加载用户配置
  const config = await syncManager.loadUserConfig('note_user_001', [
    'theme', 'font_size', 'sort_order', 'auto_sync'
  ]);
  console.info(`[Demo] 加载的配置: ${JSON.stringify(config)}`);

  // 监听数据变化
  syncManager.onAccountDataChange('com.example.notes', 'note_user_001', (accountInfo) => {
    console.info(`[Demo] 账户数据已更新: ${accountInfo.name}`);
    // 重新加载配置
  });

  // 触发数据同步
  await syncManager.syncAccountData('note_user_001', {
    key: 'last_note_id',
    value: 'note_20240101_001',
  });
}

四、踩坑与注意事项

4.1 账户名命名规范

账户名有严格的格式要求,不符合规范的名称会被直接拒绝:

// ✅ 正确的命名
const validNames = ['user_001', 'zhangsan', 'test_account'];

// ❌ 错误的命名(会导致创建失败)
const invalidNames = [
  '用户001',       // 不支持中文
  'user-001',      // 不支持连字符
  'user.001',      // 不支持点号
  'user 001',      // 不支持空格
  '',              // 空字符串
];

4.2 跨应用授权的权限声明

跨应用授权需要在 module.json5 中声明相关权限:

{
  "requestPermissions": [
    {
      "name": "ohos.permission.GET_APP_ACCOUNTS",
      "reason": "$string:app_account_reason"
    }
  ]
}

踩坑:即使声明了权限,跨应用访问也需要目标应用主动调用 setAppAccess 开放访问权限。这不是声明了就能用的,必须双方配合。

4.3 令牌安全存储

OAuth 令牌属于敏感数据,不要直接存储在自定义数据中:

// ❌ 危险:将令牌存储在自定义数据中(可能被其他应用读取)
await manager.setCustomData('user_001', 'access_token', token);

// ✅ 安全:使用专门的凭证管理接口
await manager.createAccountCredential('user_001', 'OAuth2', token);

// ✅ 更安全:令牌存储在 HUKS 加密区域
// 参见第205篇安全区域相关内容

4.4 账户删除的级联效应

删除应用账户时,相关的授权关系、令牌和自定义数据都会被级联删除。如果其他应用正在依赖这些数据,可能导致功能异常:

async function safeRemoveAccount(name: string): Promise<boolean> {
  const manager = appAccount.createAppAccountManager();

  // 1. 先检查是否有其他应用正在使用该账户
  // 2. 通知依赖应用即将删除
  // 3. 清理关联的OAuth令牌
  // 4. 最后删除账户
  try {
    await manager.removeAccount(name);
    console.info('[SafeRemove] 账户及关联数据已清理');
    return true;
  } catch (error) {
    const err = error as BusinessError;
    console.error(`[SafeRemove] 删除失败: ${err.message}`);
    return false;
  }
}

4.5 异步操作的并发控制

多个异步操作同时修改同一个账户的数据可能导致数据竞争:

// ❌ 危险:并发修改
async function unsafeConcurrentUpdate(name: string) {
  // 两个操作可能同时执行,导致数据不一致
  manager.setCustomData(name, 'key1', 'value1');
  manager.setCustomData(name, 'key2', 'value2');
}

// ✅ 安全:串行执行
async function safeSequentialUpdate(name: string) {
  await manager.setCustomData(name, 'key1', 'value1');
  await manager.setCustomData(name, 'key2', 'value2');
}

五、HarmonyOS 6 适配

5.1 API 变更

变更项 HarmonyOS 5 HarmonyOS 6
账户创建 createAccount(name) 新增 createAccountFull(name, options)
授权管理 setAppAccess 新增 setAppAccessWithScope 支持细粒度权限范围
令牌管理 createAccountCredential 新增 createCredentialWithExpiry 支持令牌过期时间
数据同步 setCustomData 新增 syncCustomData 原生同步API
事件监听 on('accountChange') 新增 on('credentialChange') 令牌变化通知

5.2 迁移指南

// HarmonyOS 5 写法
await manager.createAccount('user_001');

// HarmonyOS 6 推荐写法
const options: appAccount.CreateAccountOptions = {
  customData: {
    'nickname': '张三',
    'avatar': 'avatar_001.png',
  },
  // HarmonyOS 6 新增:预设授权列表
  authorizedApps: ['com.example.health'],
};
await manager.createAccountFull('user_001', options);

5.3 细粒度授权范围

HarmonyOS 6 支持更精细的授权范围控制,不再只是"全部授权"或"不授权":

// HarmonyOS 6: 按范围授权
const scopes = ['profile:read', 'friends:read', 'health:write'];
await manager.setAppAccessWithScope('user_001', 'com.example.health', true, scopes);

六、总结

核心知识点回顾

应用账户(appAccount)
├── 基础操作
│   ├── 创建 ── createAccount / createAccountFull
│   ├── 查询 ── queryAllAccounts / getAccountsByOwner
│   ├── 删除 ── removeAccount(级联删除关联数据)
│   └── 自定义数据 ── setCustomData / getCustomData
├── 跨应用授权
│   ├── 授权方 ── setAppAccess / setAppAccessWithScope
│   ├── 请求方 ── getAuthorizerInterface / getAccountCredential
│   ├── 令牌管理 ── createAccountCredential
│   └── 撤销授权 ── setAppAccess(name, app, false)
├── 数据同步
│   ├── 自定义数据 ── 键值对存储,支持跨设备同步
│   ├── 变化监听 ── on('accountChange')
│   └── 同步触发 ── syncCustomData
└── 注意事项
    ├── 命名规范 ── 仅支持字母、数字、下划线
    ├── 权限声明 ── GET_APP_ACCOUNTS
    ├── 令牌安全 ── 使用凭证接口而非自定义数据
    ├── 级联删除 ── 删除账户会清除所有关联数据
    └── 并发控制 ── 避免同时修改同一账户数据

应用账户是 HarmonyOS 生态内"一次登录,全生态通行"的技术基石。理解了跨应用授权、OAuth 令牌管理和数据同步机制,你就能构建出流畅的多应用协同体验。记住:应用账户不是简单的用户名密码存储,而是一套完整的跨应用身份互通体系

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。