微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

ios 中通过标头进行 AWS 授权失败

如何解决ios 中通过标头进行 AWS 授权失败

我为 GET 请求创建了一个名为 AWSS3RequestSignerGET 的类。还要创建 StringData 扩展以生成字节数组。下面给出的所有代码。如果要运行此代码需要导入CommonCrypto。此请求适用于 PUT,但不适用于 GET。 我仅删除GET 请求中的正文部分。我使用的是 accessKeyId 请求中使用的相同 secretAccessKeyPUT,但出现以下错误

{"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 举报,一经查实,本站将立刻删除。