Files
simapi-cj/src/helpers/SimApiAesBodyChecker.cj
T
xrain ea31bd9b6a refactor: 删除仅有空构造器的 public init() {}——编译器自动提供无参构造
删除(类无其他构造器):
- SimApiBaseModel / SimApiLoggerProvider / SimApiSignProviderBase / AesBodyProviderBase
- SimApiResponseFilter / SimApiAuthCenterOptions / SimApiExceptionOptions
- SimApiHttpClientOptions / SimApiOptions / SimApiSynapseOptions / SimApiRouteOptions
- SimApiStorageOptions / SimApiRequestLogOptions / SimApiJobServer / SimApiAuthOption
- AuthDto 5 个纯 POCO(AppAndProfileItem/ConfirmResponse/LoginInfoResponse/
  GroupRelatedItem/GroupDetailTreeNode)/ AesBodyRequest

保留(有带参构造器,空 init 是反序列化/绑定必需):
- GetCodeResponse / PermissionItem / SimApiBaseRequest 系列 / PageResponse
- SimApiLoginItem / SimApiDocGroup / SimApiStorage 相关 / 各 DTO
2026-08-18 00:59:48 +08:00

115 lines
3.8 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* Copyright (c) 2025 SimcuTeam. All rights reserved.
* 移植自 C# 项目 SimApiE:\simcu\simapi-net),遵循 MIT 许可证。
*/
package simapi.helpers
import std.collection.*
import std.io.*
import simapi_serialization.*
import soulsoft_web_http.*
import simapi.communications.*
import simapi.exceptions.*
import simapi.interfaces.*
/**
* AES body 请求({"data": "密文"},对齐 C# SimApiOneFieldRequest<string>)。
*/
public class AesBodyRequest {
public var _data: String = ""
}
/**
* 服务端 AES body 解密校验器(对齐 C# ModelBinders/AesBodyModelBinder)。
*
* 仓颉无 ModelBinder 机制,按项目惯例由控制器在方法开头调用:
* let jsonStr = SimApiAesBodyChecker.decryptBody(context, provider)
* let request = JsonSerializer.Deserialize<XxxRequest>(jsonStr)
* 或标注 @AesBody 注解自动执行(SimApiRequestDelegateFactory)。
*
* 流程(与 C# 一致):
* 1. 读取 body 并反序列化为 {"data": "密文"}
* 2. 校验 Data 非空
* 3. 提取 appIdQuery/Header
* 4. provider.getKey(appId) 获取密钥
* 5. SimApiAesUtil.decrypt 解密得到明文 JSON 字符串
* 返回解密后的 JSON 字符串,由控制器按目标类型反序列化。
*/
public class SimApiAesBodyChecker {
private init() {}
/**
* 解密请求体,返回明文 JSON 字符串。
* @param context 当前请求上下文。
* @param provider AES 密钥提供器。
* @return 解密后的 JSON 字符串。
*/
public static func decryptBody(context: HttpContext, provider: AesBodyProviderBase): String {
// 1. 读取 body
let body = readBody(context)
if (body.isEmpty()) {
SimApiError.error(code: 400, message: "请求体不能为空")
}
// 2. 反序列化 {"data": "密文"}
let req = JsonSerializer.Deserialize<AesBodyRequest>(body)
if (req._data.isEmpty()) {
SimApiError.error(code: 400, message: "请求体缺少密文Data字段")
}
// 3. 提取 appId
var appId: ?String = None
if (let Some(name) <- provider.appIdName) {
if (!name.isEmpty()) {
appId = getParam(context, name)
if (appId == None || appId == Some("")) {
SimApiError.error(code: 400, message: "未找到${name}")
}
}
}
// 4. 获取密钥
let key = provider.getKey(appId)
if (key == None || key == Some("")) {
SimApiError.error(code: 400, message: "获取密钥失败(应用不存在或密钥未配置)")
}
// 5. 解密
let jsonStr = SimApiAesUtil.decrypt(req._data, key.getOrThrow())
if (jsonStr.isEmpty()) {
SimApiError.error(code: 400, message: "解密失败")
}
jsonStr
}
private static func readBody(context: HttpContext): String {
try {
context.request.enableBuffering()
var buffer = Array<Byte>(4096, repeat: 0)
var sb = StringBuilder()
var read = context.request.body.read(buffer)
while (read > 0) {
sb.appendFromUtf8(buffer.slice(0, read))
read = context.request.body.read(buffer)
}
// 重置流位置,供后续业务读取
if (let seekable: Seekable <- context.request.body) {
seekable.seek(SeekPosition.Begin(0))
}
sb.toString()
} catch (ex: Exception) {
SimApiError.error(code: 400, message: "读取请求体失败: ${ex.message}")
}
""
}
private static func getParam(context: HttpContext, name: String): ?String {
let q = context.request.query.get(name)
if (q != None && q != Some("")) {
return q
}
context.request.headers.get(name)
}
}