1
This commit is contained in:
@@ -108,6 +108,7 @@
|
|||||||
0498BD782EE04286006CC1D5 /* KBHomeVM.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BD772EE04286006CC1D5 /* KBHomeVM.m */; };
|
0498BD782EE04286006CC1D5 /* KBHomeVM.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BD772EE04286006CC1D5 /* KBHomeVM.m */; };
|
||||||
0498BD7B2EE04518006CC1D5 /* KBCharacter.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BD7A2EE04518006CC1D5 /* KBCharacter.m */; };
|
0498BD7B2EE04518006CC1D5 /* KBCharacter.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BD7A2EE04518006CC1D5 /* KBCharacter.m */; };
|
||||||
0498BD7E2EE04F9C006CC1D5 /* KBTag.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BD7D2EE04F9C006CC1D5 /* KBTag.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 */; };
|
049FB20B2EC1C13800FAB05D /* KBSkinBottomActionView.m in Sources */ = {isa = PBXBuildFile; fileRef = 049FB20A2EC1C13800FAB05D /* KBSkinBottomActionView.m */; };
|
||||||
049FB20E2EC1CD2800FAB05D /* KBAlert.m in Sources */ = {isa = PBXBuildFile; fileRef = 049FB20D2EC1CD2800FAB05D /* KBAlert.m */; };
|
049FB20E2EC1CD2800FAB05D /* KBAlert.m in Sources */ = {isa = PBXBuildFile; fileRef = 049FB20D2EC1CD2800FAB05D /* KBAlert.m */; };
|
||||||
049FB2112EC1F72F00FAB05D /* KBMyListCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 049FB2102EC1F72F00FAB05D /* KBMyListCell.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 = "<group>"; };
|
0498BD7A2EE04518006CC1D5 /* KBCharacter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBCharacter.m; sourceTree = "<group>"; };
|
||||||
0498BD7C2EE04F9C006CC1D5 /* KBTag.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBTag.h; sourceTree = "<group>"; };
|
0498BD7C2EE04F9C006CC1D5 /* KBTag.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBTag.h; sourceTree = "<group>"; };
|
||||||
0498BD7D2EE04F9C006CC1D5 /* KBTag.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBTag.m; sourceTree = "<group>"; };
|
0498BD7D2EE04F9C006CC1D5 /* KBTag.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBTag.m; sourceTree = "<group>"; };
|
||||||
|
0498BD832EE1B255006CC1D5 /* KBSignUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBSignUtils.h; sourceTree = "<group>"; };
|
||||||
|
0498BD842EE1B255006CC1D5 /* KBSignUtils.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBSignUtils.m; sourceTree = "<group>"; };
|
||||||
049FB2092EC1C13800FAB05D /* KBSkinBottomActionView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBSkinBottomActionView.h; sourceTree = "<group>"; };
|
049FB2092EC1C13800FAB05D /* KBSkinBottomActionView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBSkinBottomActionView.h; sourceTree = "<group>"; };
|
||||||
049FB20A2EC1C13800FAB05D /* KBSkinBottomActionView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBSkinBottomActionView.m; sourceTree = "<group>"; };
|
049FB20A2EC1C13800FAB05D /* KBSkinBottomActionView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBSkinBottomActionView.m; sourceTree = "<group>"; };
|
||||||
049FB20C2EC1CD2800FAB05D /* KBAlert.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBAlert.h; sourceTree = "<group>"; };
|
049FB20C2EC1CD2800FAB05D /* KBAlert.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBAlert.h; sourceTree = "<group>"; };
|
||||||
@@ -902,6 +905,15 @@
|
|||||||
path = VM;
|
path = VM;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
0498BD822EE1B246006CC1D5 /* Utils */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
0498BD832EE1B255006CC1D5 /* KBSignUtils.h */,
|
||||||
|
0498BD842EE1B255006CC1D5 /* KBSignUtils.m */,
|
||||||
|
);
|
||||||
|
path = Utils;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
049FB2162EC20A6600FAB05D /* BMLongPressDragCellCollectionView */ = {
|
049FB2162EC20A6600FAB05D /* BMLongPressDragCellCollectionView */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -1199,6 +1211,7 @@
|
|||||||
04FC95BF2EB1E3B1007BD342 /* Class */ = {
|
04FC95BF2EB1E3B1007BD342 /* Class */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
0498BD822EE1B246006CC1D5 /* Utils */,
|
||||||
04122F612EC5F3DF00EF7AB3 /* Pay */,
|
04122F612EC5F3DF00EF7AB3 /* Pay */,
|
||||||
7276DDA22EC1B22500804C36 /* WebView */,
|
7276DDA22EC1B22500804C36 /* WebView */,
|
||||||
048908D32EBF618E00FABA60 /* Vender */,
|
048908D32EBF618E00FABA60 /* Vender */,
|
||||||
@@ -1756,6 +1769,7 @@
|
|||||||
049FB22C2EC31F8800FAB05D /* KBGenderPickerPopView.m in Sources */,
|
049FB22C2EC31F8800FAB05D /* KBGenderPickerPopView.m in Sources */,
|
||||||
048908D22EBF611D00FABA60 /* KBHistoryMoreCell.m in Sources */,
|
048908D22EBF611D00FABA60 /* KBHistoryMoreCell.m in Sources */,
|
||||||
04FC95D82EB1EA16007BD342 /* BaseCell.m in Sources */,
|
04FC95D82EB1EA16007BD342 /* BaseCell.m in Sources */,
|
||||||
|
0498BD852EE1B255006CC1D5 /* KBSignUtils.m in Sources */,
|
||||||
0477BDF72EBC63A80055D639 /* KBTestVC.m in Sources */,
|
0477BDF72EBC63A80055D639 /* KBTestVC.m in Sources */,
|
||||||
04122F7E2EC5FC5500EF7AB3 /* KBJfPayCell.m in Sources */,
|
04122F7E2EC5FC5500EF7AB3 /* KBJfPayCell.m in Sources */,
|
||||||
049FB2402EC4B6EF00FAB05D /* KBULBridgeNotification.m in Sources */,
|
049FB2402EC4B6EF00FAB05D /* KBULBridgeNotification.m in Sources */,
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
// 仅在主 App 内需要的会话管理与 HUD 组件
|
// 仅在主 App 内需要的会话管理与 HUD 组件
|
||||||
#import "KBUserSessionManager.h"
|
#import "KBUserSessionManager.h"
|
||||||
#import "KBHUD.h"
|
#import "KBHUD.h"
|
||||||
|
#import "KBSignUtils.h"
|
||||||
|
|
||||||
NSErrorDomain const KBNetworkErrorDomain = @"com.company.keyboard.network";
|
NSErrorDomain const KBNetworkErrorDomain = @"com.company.keyboard.network";
|
||||||
|
|
||||||
@@ -44,10 +45,45 @@ NSErrorDomain const KBNetworkErrorDomain = @"com.company.keyboard.network";
|
|||||||
// 默认请求头:Accept 任意类型 + 使用项目多语言管理器设置 Accept-Language
|
// 默认请求头:Accept 任意类型 + 使用项目多语言管理器设置 Accept-Language
|
||||||
NSString *lang = [KBLocalizationManager shared].currentLanguageCode ?: KBLanguageCodeEnglish;
|
NSString *lang = [KBLocalizationManager shared].currentLanguageCode ?: KBLanguageCodeEnglish;
|
||||||
NSString *token = [KBUserSessionManager shared].accessToken ? [KBUserSessionManager shared].accessToken : @"";
|
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<NSString *, NSString *> *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 = @{
|
_defaultHeaders = @{
|
||||||
@"Accept": @"*/*",
|
@"Accept": @"*/*",
|
||||||
@"Accept-Language": lang,
|
@"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];
|
_baseURL = [NSURL URLWithString:KB_BASE_URL];
|
||||||
|
|||||||
32
keyBoard/Class/Utils/KBSignUtils.h
Normal file
32
keyBoard/Class/Utils/KBSignUtils.h
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
//
|
||||||
|
// KBSignUtils.h
|
||||||
|
// keyBoard
|
||||||
|
//
|
||||||
|
// Created by Mac on 2025/12/4.
|
||||||
|
//
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
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<NSString *, NSString *> *)params
|
||||||
|
secret:(NSString *)secret;
|
||||||
|
|
||||||
|
/// 秒级时间戳(字符串)
|
||||||
|
+ (NSString *)currentTimestamp;
|
||||||
|
|
||||||
|
/// 简单 nonce 生成(默认 16 位)
|
||||||
|
+ (NSString *)generateNonceWithLength:(NSUInteger)length;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
|
|
||||||
92
keyBoard/Class/Utils/KBSignUtils.m
Normal file
92
keyBoard/Class/Utils/KBSignUtils.m
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
//
|
||||||
|
// KBSignUtils.m
|
||||||
|
// keyBoard
|
||||||
|
//
|
||||||
|
// Created by Mac on 2025/12/4.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "KBSignUtils.h"
|
||||||
|
#import <CommonCrypto/CommonCrypto.h>
|
||||||
|
|
||||||
|
@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<NSString *, NSString *> *)params
|
||||||
|
secret:(NSString *)secret {
|
||||||
|
|
||||||
|
// 1. 过滤空值 & sign 自身
|
||||||
|
NSMutableDictionary<NSString *, NSString *> *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<NSString *> *sortedKeys = [[filtered allKeys] sortedArrayUsingSelector:@selector(compare:)];
|
||||||
|
|
||||||
|
// 3. 拼接 key=value&key2=value2...&secret=xxx
|
||||||
|
NSMutableArray<NSString *> *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
|
||||||
|
|
||||||
Reference in New Issue
Block a user