From eb7ad1a9f183661a1059211df6991c4dda8386ca Mon Sep 17 00:00:00 2001 From: CodeST <694468528@qq.com> Date: Thu, 4 Dec 2025 20:27:26 +0800 Subject: [PATCH] 1 --- keyBoard.xcodeproj/project.pbxproj | 14 ++++ keyBoard/Class/Network/KBNetworkManager.m | 38 +++++++++- keyBoard/Class/Utils/KBSignUtils.h | 32 ++++++++ keyBoard/Class/Utils/KBSignUtils.m | 92 +++++++++++++++++++++++ 4 files changed, 175 insertions(+), 1 deletion(-) create mode 100644 keyBoard/Class/Utils/KBSignUtils.h create mode 100644 keyBoard/Class/Utils/KBSignUtils.m diff --git a/keyBoard.xcodeproj/project.pbxproj b/keyBoard.xcodeproj/project.pbxproj index bdac235..a9db39c 100644 --- a/keyBoard.xcodeproj/project.pbxproj +++ b/keyBoard.xcodeproj/project.pbxproj @@ -108,6 +108,7 @@ 0498BD782EE04286006CC1D5 /* KBHomeVM.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BD772EE04286006CC1D5 /* KBHomeVM.m */; }; 0498BD7B2EE04518006CC1D5 /* KBCharacter.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BD7A2EE04518006CC1D5 /* KBCharacter.m */; }; 0498BD7E2EE04F9C006CC1D5 /* KBTag.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BD7D2EE04F9C006CC1D5 /* KBTag.m */; }; + 0498BD852EE1B255006CC1D5 /* KBSignUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BD842EE1B255006CC1D5 /* KBSignUtils.m */; }; 049FB20B2EC1C13800FAB05D /* KBSkinBottomActionView.m in Sources */ = {isa = PBXBuildFile; fileRef = 049FB20A2EC1C13800FAB05D /* KBSkinBottomActionView.m */; }; 049FB20E2EC1CD2800FAB05D /* KBAlert.m in Sources */ = {isa = PBXBuildFile; fileRef = 049FB20D2EC1CD2800FAB05D /* KBAlert.m */; }; 049FB2112EC1F72F00FAB05D /* KBMyListCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 049FB2102EC1F72F00FAB05D /* KBMyListCell.m */; }; @@ -394,6 +395,8 @@ 0498BD7A2EE04518006CC1D5 /* KBCharacter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBCharacter.m; sourceTree = ""; }; 0498BD7C2EE04F9C006CC1D5 /* KBTag.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBTag.h; sourceTree = ""; }; 0498BD7D2EE04F9C006CC1D5 /* KBTag.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBTag.m; sourceTree = ""; }; + 0498BD832EE1B255006CC1D5 /* KBSignUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBSignUtils.h; sourceTree = ""; }; + 0498BD842EE1B255006CC1D5 /* KBSignUtils.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBSignUtils.m; sourceTree = ""; }; 049FB2092EC1C13800FAB05D /* KBSkinBottomActionView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBSkinBottomActionView.h; sourceTree = ""; }; 049FB20A2EC1C13800FAB05D /* KBSkinBottomActionView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBSkinBottomActionView.m; sourceTree = ""; }; 049FB20C2EC1CD2800FAB05D /* KBAlert.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBAlert.h; sourceTree = ""; }; @@ -902,6 +905,15 @@ path = VM; sourceTree = ""; }; + 0498BD822EE1B246006CC1D5 /* Utils */ = { + isa = PBXGroup; + children = ( + 0498BD832EE1B255006CC1D5 /* KBSignUtils.h */, + 0498BD842EE1B255006CC1D5 /* KBSignUtils.m */, + ); + path = Utils; + sourceTree = ""; + }; 049FB2162EC20A6600FAB05D /* BMLongPressDragCellCollectionView */ = { isa = PBXGroup; children = ( @@ -1199,6 +1211,7 @@ 04FC95BF2EB1E3B1007BD342 /* Class */ = { isa = PBXGroup; children = ( + 0498BD822EE1B246006CC1D5 /* Utils */, 04122F612EC5F3DF00EF7AB3 /* Pay */, 7276DDA22EC1B22500804C36 /* WebView */, 048908D32EBF618E00FABA60 /* Vender */, @@ -1756,6 +1769,7 @@ 049FB22C2EC31F8800FAB05D /* KBGenderPickerPopView.m in Sources */, 048908D22EBF611D00FABA60 /* KBHistoryMoreCell.m in Sources */, 04FC95D82EB1EA16007BD342 /* BaseCell.m in Sources */, + 0498BD852EE1B255006CC1D5 /* KBSignUtils.m in Sources */, 0477BDF72EBC63A80055D639 /* KBTestVC.m in Sources */, 04122F7E2EC5FC5500EF7AB3 /* KBJfPayCell.m in Sources */, 049FB2402EC4B6EF00FAB05D /* KBULBridgeNotification.m in Sources */, diff --git a/keyBoard/Class/Network/KBNetworkManager.m b/keyBoard/Class/Network/KBNetworkManager.m index 9b628c6..bb57e9d 100644 --- a/keyBoard/Class/Network/KBNetworkManager.m +++ b/keyBoard/Class/Network/KBNetworkManager.m @@ -11,6 +11,7 @@ // 仅在主 App 内需要的会话管理与 HUD 组件 #import "KBUserSessionManager.h" #import "KBHUD.h" +#import "KBSignUtils.h" NSErrorDomain const KBNetworkErrorDomain = @"com.company.keyboard.network"; @@ -44,10 +45,45 @@ NSErrorDomain const KBNetworkErrorDomain = @"com.company.keyboard.network"; // 默认请求头:Accept 任意类型 + 使用项目多语言管理器设置 Accept-Language NSString *lang = [KBLocalizationManager shared].currentLanguageCode ?: KBLanguageCodeEnglish; NSString *token = [KBUserSessionManager shared].accessToken ? [KBUserSessionManager shared].accessToken : @""; + NSString *appId = @"loveKeyboard"; + NSString *secret = @"kZJM39HYvhxwbJkG1fmquQRVkQiLAh2H"; // 和服务端保持一致 + NSString *timestamp = [KBSignUtils currentTimestamp]; + NSString *nonce = [KBSignUtils generateNonceWithLength:16]; + + // 业务参数(body 或 query) + NSDictionary *bodyParams = @{ + + }; + + // 1. 组装参与签名的所有参数 + NSMutableDictionary *signParams = [NSMutableDictionary dictionary]; + signParams[@"appId"] = appId; + signParams[@"timestamp"] = timestamp; + signParams[@"nonce"] = nonce; + + // 如果还有 query 参数也塞进来 + // signParams[@"lang"] = @"zh"; + + // 把 body 里的字段也加入签名参数 + [bodyParams enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + if ([obj isKindOfClass:[NSString class]]) { + signParams[key] = obj; + } else { + signParams[key] = [obj description]; + } + }]; + + // 2. 计算签名 + NSString *sign = [KBSignUtils signWithParams:signParams secret:secret]; _defaultHeaders = @{ @"Accept": @"*/*", @"Accept-Language": lang, - @"auth-token" : token + @"auth-token" : token, + @"X-Sign" : sign, + @"X-Timestamp" : timestamp, + @"X-Nonce" : nonce, + @"X-App-Id" : appId + }; // 设置基础域名,路径可相对该地址拼接 _baseURL = [NSURL URLWithString:KB_BASE_URL]; diff --git a/keyBoard/Class/Utils/KBSignUtils.h b/keyBoard/Class/Utils/KBSignUtils.h new file mode 100644 index 0000000..958fce4 --- /dev/null +++ b/keyBoard/Class/Utils/KBSignUtils.h @@ -0,0 +1,32 @@ +// +// KBSignUtils.h +// keyBoard +// +// Created by Mac on 2025/12/4. +// +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface KBSignUtils : NSObject + +/// URL 编码(与后端保持一致) ++ (NSString *)urlEncode:(NSString *)value; + +/// HMAC-SHA256,返回十六进制小写字符串 ++ (NSString *)hmacSHA256:(NSString *)data secret:(NSString *)secret; + +/// 生成签名:传入参与签名的所有参数(不含 sign 自身) ++ (NSString *)signWithParams:(NSDictionary *)params + secret:(NSString *)secret; + +/// 秒级时间戳(字符串) ++ (NSString *)currentTimestamp; + +/// 简单 nonce 生成(默认 16 位) ++ (NSString *)generateNonceWithLength:(NSUInteger)length; + +@end + +NS_ASSUME_NONNULL_END + diff --git a/keyBoard/Class/Utils/KBSignUtils.m b/keyBoard/Class/Utils/KBSignUtils.m new file mode 100644 index 0000000..4d03036 --- /dev/null +++ b/keyBoard/Class/Utils/KBSignUtils.m @@ -0,0 +1,92 @@ +// +// KBSignUtils.m +// keyBoard +// +// Created by Mac on 2025/12/4. +// + +#import "KBSignUtils.h" +#import + +@implementation KBSignUtils + ++ (NSString *)urlEncode:(NSString *)value { + if (!value) return @""; + // 和 Swift 里的 .urlQueryAllowed 类似 + NSCharacterSet *allowed = [NSCharacterSet URLQueryAllowedCharacterSet]; + NSString *encoded = [value stringByAddingPercentEncodingWithAllowedCharacters:allowed]; + return encoded ?: value; +} + ++ (NSString *)hmacSHA256:(NSString *)data secret:(NSString *)secret { + const char *cKey = [secret cStringUsingEncoding:NSUTF8StringEncoding]; + const char *cData = [data cStringUsingEncoding:NSUTF8StringEncoding]; + + unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH]; + + CCHmac(kCCHmacAlgSHA256, + cKey, + strlen(cKey), + cData, + strlen(cData), + cHMAC); + + // 转十六进制小写字符串 + NSMutableString *output = [NSMutableString stringWithCapacity:CC_SHA256_DIGEST_LENGTH * 2]; + for (int i = 0; i < CC_SHA256_DIGEST_LENGTH; i++) { + [output appendFormat:@"%02x", cHMAC[i]]; + } + return output; +} + ++ (NSString *)signWithParams:(NSDictionary *)params + secret:(NSString *)secret { + + // 1. 过滤空值 & sign 自身 + NSMutableDictionary *filtered = [NSMutableDictionary dictionary]; + [params enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *obj, BOOL *stop) { + if (!obj || obj.length == 0) return; + if ([[key lowercaseString] isEqualToString:@"sign"]) return; + filtered[key] = obj; + }]; + + // 2. 按 key 字典序排序 + NSArray *sortedKeys = [[filtered allKeys] sortedArrayUsingSelector:@selector(compare:)]; + + // 3. 拼接 key=value&key2=value2...&secret=xxx + NSMutableArray *components = [NSMutableArray array]; + for (NSString *key in sortedKeys) { + NSString *value = filtered[key] ?: @""; + NSString *encodedValue = [self urlEncode:value]; + NSString *part = [NSString stringWithFormat:@"%@=%@", key, encodedValue]; + [components addObject:part]; + } + + NSString *encodedSecret = [self urlEncode:secret]; + NSString *secretPart = [NSString stringWithFormat:@"secret=%@", encodedSecret]; + [components addObject:secretPart]; + + NSString *dataString = [components componentsJoinedByString:@"&"]; + + // 4. HMAC-SHA256 + NSString *sign = [self hmacSHA256:dataString secret:secret]; + return sign; +} + ++ (NSString *)currentTimestamp { + NSTimeInterval ts = [[NSDate date] timeIntervalSince1970]; + long long seconds = (long long)ts; + return [NSString stringWithFormat:@"%lld", seconds]; +} + ++ (NSString *)generateNonceWithLength:(NSUInteger)length { + // 用 UUID 生成,去掉 - , 再截取前 length 位 + NSString *uuid = [[NSUUID UUID].UUIDString stringByReplacingOccurrencesOfString:@"-" withString:@""]; + if (length == 0 || length > uuid.length) { + return uuid; + } + return [uuid substringToIndex:length]; +} + +@end +