jsdw_ios/QuickLocation/API/SignPlugin.swift

83 lines
2.7 KiB
Swift
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.

import Foundation
import Moya
import CommonCrypto
/// JiaMiKey 的 MD5,预计算避免每次请求都算
private let jiaMiKeyMD5: String = {
let key = "857d69d374694c1de46486d3bdaaac43"
return SignPlugin.md5(key)
}()
/// 请求签名 Plugin
final class SignPlugin: PluginType {
func prepare(_ request: URLRequest, target: any TargetType) -> URLRequest {
var mutableRequest = request
guard let url = request.url else { return mutableRequest }
let timestamp = String(format: "%.0lf", Date().timeIntervalSince1970)
let nonce = randomString(length: 32)
var queryDict: [String: String] = [
"timestamp": timestamp,
"nonce": nonce
]
// 收集 URL 已有的 query 参数,一并纳入签名
if let components = URLComponents(url: url, resolvingAgainstBaseURL: false),
let queryItems = components.queryItems {
for item in queryItems {
queryDict[item.name] = item.value ?? ""
}
}
let bodyString: String
if let httpBody = request.httpBody, !httpBody.isEmpty {
bodyString = String(data: httpBody, encoding: .utf8) ?? ""
} else {
bodyString = ""
}
let queryString = sortedQueryString(queryDict)
let signStr: String
if bodyString.isEmpty {
signStr = queryString + "&" + jiaMiKeyMD5
} else {
signStr = queryString + "&" + bodyString + "&" + jiaMiKeyMD5
}
let signature = Self.md5(signStr)
// 剥离旧 query,替换为完整的签名 query
let signedQuery = queryString + "&signature=" + signature
var components = URLComponents(url: url, resolvingAgainstBaseURL: false)
components?.percentEncodedQuery = signedQuery.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
if let newURL = components?.url {
mutableRequest.url = newURL
}
return mutableRequest
}
private func sortedQueryString(_ dict: [String: String]) -> String {
dict
.sorted { $0.key < $1.key }
.map { "\($0.key)=\($0.value)" }
.joined(separator: "&")
}
private func randomString(length: Int) -> String {
let chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
return String((0..<length).map { _ in chars.randomElement()! })
}
fileprivate static func md5(_ string: String) -> String {
let cStr = string.cString(using: .utf8)
let length = CC_LONG(strlen(cStr!))
var digest = [UInt8](repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH))
CC_MD5(cStr, length, &digest)
return digest.map { String(format: "%02x", $0) }.joined()
}
}