如何解决ios 中通过标头进行 AWS 授权失败
我为 GET 请求创建了一个名为 AWSS3RequestSignerGET 的类。还要创建 String
和 Data
扩展以生成字节数组。下面给出的所有代码。如果要运行此代码需要导入CommonCrypto
。此请求适用于 PUT
,但不适用于 GET
。
我仅删除了 GET
请求中的正文部分。我使用的是 accessKeyId
请求中使用的相同 secretAccessKey
和 PUT
,但出现以下错误
{"message":"我们计算的请求签名与 您提供的签名。检查您的 AWS 秘密访问密钥和签名 方法。有关详细信息,请参阅服务文档。"}
class AWSS3RequestSignerGET: NSObject {
private let hmacShaTypestring = "AWS4-HMAC-SHA256"
private let awsRegion = "us-west-1"
private let serviceType = "es"
private let aws4Request = "aws4_request"
private let iso8601Formatter: DateFormatter = {
let formatter = DateFormatter()
formatter.calendar = Calendar(identifier: .iso8601)
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.timeZone = TimeZone(secondsFromGMT: 0)
formatter.dateFormat = "yyyyMMdd'T'HHmmssXXXXX"
return formatter
}()
private func iso8601() -> (full: String,short: String) {
let date = iso8601Formatter.string(from: Date())
let index = date.index(date.startIndex,offsetBy: 8)
let shortDate = date.substring(to: index)
return (full: date,short: shortDate)
}
func signGET(request: URLRequest,secretSigningKey: String,accessKeyId: String) -> URLRequest? {
var signedRequest = request
let date = iso8601()
guard let url = signedRequest.url,let host = url.host
else { return .none }
signedRequest.addValue(host,forHTTPHeaderField: "Host")
signedRequest.addValue(date.full,forHTTPHeaderField: "X-Amz-Date")
guard let headers = signedRequest.allHTTPHeaderFields,let method = signedRequest.httpMethod
else { return .none }
let signedHeaders = headers.map{ $0.key.lowercased() }.sorted().joined(separator: ";")
let canonicalRequestHash = [
method,url.path,url.query ?? "",headers.map{ $0.key.lowercased() + ":" + $0.value }.sorted().joined(separator: "\n"),"",signedHeaders
].joined(separator: "\n").sha256()
let credential = [date.short,awsRegion,serviceType,aws4Request].joined(separator: "/")
let stringToSign = [
hmacShaTypestring,date.full,credential,canonicalRequestHash
].joined(separator: "\n")
guard let signature = signatureWith(stringToSign: stringToSign,secretAccessKey: secretSigningKey,shortDateString: date.short)
else { return nil }
let authorization = hmacShaTypestring + " Credential=" + accessKeyId + "/" + credential + ",SignedHeaders=" + signedHeaders + ",Signature=" + signature
signedRequest.addValue(authorization,forHTTPHeaderField: "Authorization")
return signedRequest
}
private func getCredential(date: String,accessKeyId: String) -> String {
let credential = [date,aws4Request].joined(separator: "/")
return credential
}
/*
DateKey = HMAC-SHA256("AWS4"+"<SecretAccessKey>","<YYYYMMDD>")
DateRegionKey = HMAC-SHA256(<DateKey>,"<aws-region>")
DateRegionServiceKey = HMAC-SHA256(<DateRegionKey>,"<aws-service>")
SigningKey = HMAC-SHA256(<DateRegionServiceKey>,"aws4_request")
*/
private func signatureWith(stringToSign: String,secretAccessKey: String,shortDateString: String) -> String? {
let firstKey = "AWS4" + secretAccessKey
let dateKey = shortDateString.hmac(keyString: firstKey)
let dateRegionKey = awsRegion.hmac(keyData: dateKey)
let dateRegionServiceKey = serviceType.hmac(keyData: dateRegionKey)
let signingKey = aws4Request.hmac(keyData: dateRegionServiceKey)
let signature = stringToSign.hmac(keyData: signingKey)
return signature.toHexString()
}
}
extension String {
func sha256() -> String {
guard let data = self.data(using: .utf8) else { return "" }
var hash = [UInt8](repeating: 0,count: Int(CC_SHA256_DIGEST_LENGTH))
data.withUnsafeBytes {
_ = CC_SHA256($0,CC_LONG(data.count),&hash)
}
let outputData = Data(bytes: hash)
return outputData.toHexString()
}
func hmac(keyString: String) -> Data {
var digest = [UInt8](repeating: 0,count: Int(CC_SHA256_DIGEST_LENGTH))
CCHmac(CCHmacAlgorithm(kCCHmacAlgSHA256),keyString,keyString.count,self,self.count,&digest)
let data = Data(bytes: digest)
return data
}
func hmac(keyData: Data) -> Data {
let keyBytes = keyData.bytes()
let data = self.cString(using: String.Encoding.utf8)
let dataLen = Int(self.lengthOfBytes(using: String.Encoding.utf8))
var result = [UInt8](repeating: 0,keyBytes,keyData.count,data,dataLen,&result);
return Data(bytes: result)
}
}
extension Data {
func toHexString() -> String {
let hexString = self.map{ String(format:"%02x",$0) }.joined()
return hexString
}
func bytes() -> [UInt8] {
let array = [UInt8](self)
return array
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。