2026-07-16代码优化.md 7.28 KB

2026-07-16 泰额版代码优化

本文档说明 泰额版后端 当日对 tenant-select 出参、默认管理员凭据加密及 Web 登录入参的改造。仅涉及泰额版 Yi.Abp.Net8,前端需同步对接。


一、变更概述

说明
接口 GET /api/app/th-multi-tenancy/tenant-select
目的 登录页展示租户列表时不再暴露租户 Id、数据库连接串;改为返回创建时间与可解密的默认管理员凭据
登录 POST /api/app/th-web-auth/login 支持 tenantName 替代 tenantId
配置 新增 FoodLabeling:TenantSelectCrypto:SecretKey

二、tenant-select 出参变更

2.1 新旧字段对比

旧字段 新字段 说明
id 已移除,不再返回租户 Guid
name name 保留,租户名称
creationTime 新增,租户创建时间(主库 yitenant
loginAccount 新增,默认管理员账号,固定为 admin(与 UserDataSeed 一致)
password 新增,AES-CBC 加密后的 Base64 密文(库内不可逆哈希)
passwordSalt 新增,AES IV 的 Base64,前端解密时使用
tenantConnectionString / 连接串相关 从未在此接口返回;仍不暴露

2.2 出参示例

[
  {
    "name": "Default",
    "creationTime": "2026-01-15T10:30:00",
    "loginAccount": "admin",
    "password": "xK3mP9vL2nQ8wR1sT4uV7yZ0aB5cD6eF8gH9iJ0kL1m=",
    "passwordSalt": "AbCdEfGhIjKlMnOpQrStUvWxYz0123=="
  }
]

每条记录的 password / passwordSalt 因随机 IV 而不同;明文来源均为 RbacOptions.AdminPassword(当前默认 123456)。


三、密码加盐加密与前端解密

3.1 算法约定

算法 AES-256-CBC
填充 PKCS7
Key SHA256(UTF8(SecretKey)) → 32 字节
IV 每次加密随机 16 字节,Base64 写入 passwordSalt
密文 Base64 写入 password
明文 RbacOptions.AdminPassword(appsettings,与种子管理员一致)

3.2 后端配置

appsettings.json

"FoodLabeling": {
  "TenantSelectCrypto": {
    "SecretKey": "FoodLabelingThTenantSelect2026Key!"
  }
}
  • SecretKey 为前后端约定的字符串,不要求本身为 32 字节;后端用 SHA256 派生 AES-256 密钥。
  • 生产环境请更换为足够长度的随机字符串,并与前端构建配置保持一致。

3.3 前端解密(CryptoJS 示例)

import CryptoJS from 'crypto-js';

const SECRET_KEY = 'FoodLabelingThTenantSelect2026Key!'; // 与后端 TenantSelectCrypto:SecretKey 一致

function decryptTenantPassword(passwordBase64, passwordSaltBase64) {
  const key = CryptoJS.SHA256(CryptoJS.enc.Utf8.parse(SECRET_KEY));
  const iv = CryptoJS.enc.Base64.parse(passwordSaltBase64);
  const cipher = CryptoJS.enc.Base64.parse(passwordBase64);

  const decrypted = CryptoJS.AES.decrypt(
    { ciphertext: cipher },
    key,
    { iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 },
  );

  return decrypted.toString(CryptoJS.enc.Utf8);
}

3.4 前端解密(Web Crypto 伪代码)

async function decryptTenantPassword(passwordBase64, passwordSaltBase64) {
  const secretKey = 'FoodLabelingThTenantSelect2026Key!';
  const keyMaterial = await crypto.subtle.importKey(
    'raw',
    await crypto.subtle.digest('SHA-256', new TextEncoder().encode(secretKey)),
    { name: 'AES-CBC' },
    false,
    ['decrypt'],
  );
  const iv = Uint8Array.from(atob(passwordSaltBase64), (c) => c.charCodeAt(0));
  const cipher = Uint8Array.from(atob(passwordBase64), (c) => c.charCodeAt(0));
  const plain = await crypto.subtle.decrypt({ name: 'AES-CBC', iv }, keyMaterial, cipher);
  return new TextDecoder().decode(plain);
}

3.5 安全说明

  • 接口为 匿名可访问,密文仅降低明文密码在传输/展示中的直接暴露风险,不能替代 HTTPS 与生产环境改密策略。
  • 解密后的密码仅用于登录表单预填或一键登录;请勿持久化明文密码。

四、Web 登录:tenantName 替代 tenantId

tenant-select 不再返回 id 后,Web 登录须使用 租户名称

4.1 入参变更

字段 必填 说明
tenantId tenantName 二选一
tenantName tenantId 二选一,推荐
userName 账号或邮箱;adminadmin@example.com 均可
password 明文密码

二者均为空时返回:请指定租户 Id 或租户名称

4.2 登录示例(curl)

curl -X POST "http://127.0.0.1:19002/api/app/th-web-auth/login" \
  -H "Content-Type: application/json" \
  -d "{\"tenantName\":\"Default\",\"userName\":\"admin\",\"password\":\"123456\"}"

4.3 出参(不变)

{
  "token": "eyJhbGciOiJIUzI1NiIs...",
  "refreshToken": "...",
  "tenantId": "11111111-1111-1111-1111-111111111111",
  "tenantName": "Default"
}

Token 内仍写入真实 TenantId Guid;后续业务 API 行为不变。


五、泰额 App 登录说明

POST /api/app/th-app-auth/login 本次未改,仍要求入参 tenantId(Guid)。

若 App 端也需要去掉 tenantId,需单独改造 ThAppLoginInputVoThAppAuthAppService,并与移动端联调。


六、相关接口(当日其它优化,可选)

  • 开通租户 POST /api/app/th-tenant-provisioning/provision:创建租户后可在后台异步初始化业务库(DatabaseInitializing / InitializeTenantDatabase)。
  • 同步初始化 POST /api/app/th-tenant-provisioning/initialize-tenant-database/{tenantId}:补跑租户库 CodeFirst + Seed。

与本次 tenant-select 改造无直接冲突;平台管理员仍通过 provision 创建租户,登录页通过 tenant-select + tenantName 登录。


七、改动文件列表(后端)

文件 变更
FoodLabeling.Th.Application.Contracts/Dtos/MultiTenancy/ThTenantSelectDto.cs 出参字段调整
FoodLabeling.Th.Application.Contracts/Options/FoodLabelingThTenantSelectCryptoOptions.cs 新增加密配置
FoodLabeling.Th.Application/MultiTenancy/TenantSelectCredentialCipher.cs AES-CBC 加密
FoodLabeling.Th.Application/MultiTenancy/ThTenantSelectConsts.cs 默认 admin 账号常量
FoodLabeling.Th.Application/MultiTenancy/TenantResolveHelper.cs 支持 tenantName 解析
FoodLabeling.Th.Application/Services/ThMultiTenancyAppService.cs tenant-select 映射与加密
FoodLabeling.Th.Application.Contracts/Dtos/Auth/ThWebLoginInputVo.cs TenantId 可选 + TenantName
FoodLabeling.Th.Application/Services/ThWebAuthAppService.cs 按名称登录
FoodLabeling.Th.Application/FoodLabelingThApplicationModule.cs 注册加密配置
src/Yi.Abp.Web/appsettings.json TenantSelectCrypto 节点

八、前端对接 checklist

  • [ ] 更新 ThTenantSelectDto 类型,移除 id,增加 creationTime / loginAccount / password / passwordSalt
  • [ ] 配置与后端一致的 SecretKey,解密 password 后填入登录表单(若需)
  • [ ] 登录请求改传 tenantName: selected.name,不再依赖 tenantId
  • [ ] 登录成功后仍保存响应中的 tenantId 供业务 API / __tenant 头使用