外部 HTTP 路径由部署的 servlet context 与 Controller 映射共同组成(默认配置 context 为 /main-service)。本手册 13 个端点的 Controller 映射前缀:/main-api/device/data-acquisition-device 与 /main-api/device/device-share(第一代 ForPersonalSpace)、/main-api/v1/retail/device/data-acquisition-device 与 /system-api/v1/retail/user-center/user(第二代 /v1/retail)。base URL、方法与参数位置以清单层与 Swagger 为准(device · 采集设备、device · 设备分享、user-center · user 用户),不能按路径名称推断。
服务端凭据是 AES 加密 JWT,客户端以 Authorization: Bearer <AES 加密的 JWT> 携带。处理链先按配置的多把密钥(security.jwt.enc-keys)逐把尝试 AES 解密,再以签名密钥(security.jwt.signing-key)验签,两步任一失败都按未认证处理。要点:
security.jwt.token-header-name,默认 Authorization);请求头缺失时,服务端兼容从同名请求参数读取凭据。Bearer 前缀必须存在;客户端不能自行解密、拼接或改写凭据内容,凭据由登录/注册接口签发,过期或失效后必须重新获取(响应形态见错误响应差异)。JWT claims 中的 tenantId 在认证成功后进入当前认证 details;MyBatis-Plus TenantLine 拦截器经 TenantIdSupplierExecutor(优先显式执行器上下文,否则取认证 details 的 tenantId)自动为每条 SQL 注入 tenant_id 过滤,插入自动填充。因此:
tenantId 参数切换租户;空间级切换是服务端内部能力,不对 App 开放。跨租户读只发生在服务端内部显式忽略租户的路径上。anyRequest().authenticated();白名单(swagger、error、登录、验证码、general/public 等)不含任何 retail / ForPersonalSpace 路径,13 个端点全部需要有效凭据。@PreAuthorize 权限注解——没有细粒度权限码,持有有效 JWT 即可调用。同一 Controller 的管理端 CRUD 均要求 device-data-acquisition-device:* / device-share:* 权限,形成对比。status=1000(见错误响应差异)。常规响应的公共底座为 timestamp、status、error、localizedError、path、extraData 和 data;data 的形状由操作决定。HTTP status 与 JSON status 是两层信号,调用方不能仅以 HTTP 2xx 判成功,判定口径见错误响应差异。
适用后端基线:源码归纳 @ 2026-09-14。以下均为源码归纳结论:凭据解析与验签、同名请求参数兜底、无状态会话;认证失败按 200/1000 兼容形态返回;tenantId 取自凭据 claims 并经租户拦截器生效;匿名白名单不含 retail 路径(retail 端点默认无方法级授权注解,与管理端形成对比);响应信封底座与 servlet context 前缀按上文约定。