ios - 从 Swift 访问 Azure 表存储

标签 ios swift http azure authentication

我想从 Swift 访问 azure 表存储。 制作表头的指令是here 但是,我尝试构建请求但无法使其工作:

 let urlString =   "https://<myaccount>.table.core.windows.net/MyTable"
    let storageUrl = NSURL( string: urlString)
    let request = NSMutableURLRequest(URL: storageUrl!)

    //making the date
    let currentDate = NSDate()
    let httpFormatter = NSDateFormatter()
    httpFormatter.timeZone = NSTimeZone(abbreviation: "GMT")
    httpFormatter.dateFormat = "EEE',' dd MMM yyyy HH':'mm':'ss z"
    let httpTime = httpFormatter.stringFromDate(currentDate)
    print(httpTime)

    let signingString = "GET\n\n\n\(httpTime)\n/<myaccount>/MyTable"
    print(signingString)


    let keyString = <myKeyString>
    let keyData = keyString.dataUsingEncoding(NSUTF8StringEncoding,allowLossyConversion: false)!
    let signingData = signingString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
    let length:Int = Int(CC_SHA256_DIGEST_LENGTH)
    let hashResult = UnsafeMutablePointer<CUnsignedChar>.alloc(length)
    CCHmac(CCHmacAlgorithm(kCCHmacAlgSHA256), keyData.bytes, Int(keyData.length), signingData.bytes, Int(signingData.length), hashResult)
    print(hashResult)
    let hash = NSData(bytes: hashResult, length: Int(CC_SHA256_DIGEST_LENGTH))
    let hashString = hash.base64EncodedStringWithOptions(NSDataBase64EncodingOptions([]))
    hashResult.destroy()
    //print(hashString)

    request.setValue("SharedKeyLite <myaccount>:\(hashString)", forHTTPHeaderField: "Authorization")
    request.setValue("0", forHTTPHeaderField: "Content-Length")
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    request.setValue(httpTime, forHTTPHeaderField: "x-ms-date")
    request.setValue("", forHTTPHeaderField: "Date")
    request.HTTPMethod = "GET"

    NSURLSession.sharedSession().dataTaskWithRequest(request, completionHandler: { (data, response, error) in
        if let data = data {
            let datastring = NSString(data:data, encoding:NSUTF8StringEncoding)
            print( datastring! )

            //print(response)

        } else {

            print( error )

        }
    }).resume()

在下面的正确答案之后,我对字符串进行了扩展,因此 hmac 签名非常容易做到:

//
//  CryptoExtensions.swift
//  LaochTestProject
//
//  Created by Lars Christoffersen on 02/01/16.
//  Copyright © 2016 Lars Christoffersen. All rights reserved.
//

import Foundation


    enum CryptoAlgorithm {
        case MD5, SHA1, SHA224, SHA256, SHA384, SHA512

        var HMACAlgorithm: CCHmacAlgorithm {
            var result: Int = 0
            switch self {
            case .MD5:      result = kCCHmacAlgMD5
            case .SHA1:     result = kCCHmacAlgSHA1
            case .SHA224:   result = kCCHmacAlgSHA224
            case .SHA256:   result = kCCHmacAlgSHA256
            case .SHA384:   result = kCCHmacAlgSHA384
            case .SHA512:   result = kCCHmacAlgSHA512
            }
            return CCHmacAlgorithm(result)
        }

        var digestLength: Int {
            var result: Int32 = 0
            switch self {
            case .MD5:      result = CC_MD5_DIGEST_LENGTH
            case .SHA1:     result = CC_SHA1_DIGEST_LENGTH
            case .SHA224:   result = CC_SHA224_DIGEST_LENGTH
            case .SHA256:   result = CC_SHA256_DIGEST_LENGTH
            case .SHA384:   result = CC_SHA384_DIGEST_LENGTH
            case .SHA512:   result = CC_SHA512_DIGEST_LENGTH
            }
            return Int(result)
        }
    }

    extension String {

        func hmac(algorithm: CryptoAlgorithm, key: String) -> String {


            let strData = self.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
            let keyData = NSData(base64EncodedString: key, options: NSDataBase64DecodingOptions.IgnoreUnknownCharacters)!
            let digestLen = algorithm.digestLength
            let hashResult = UnsafeMutablePointer<CUnsignedChar>.alloc(digestLen)
            CCHmac(algorithm.HMACAlgorithm, keyData.bytes, Int(keyData.length), strData.bytes, Int(strData.length), hashResult)
            let hash = NSData(bytes: hashResult, length: digestLen )
            let hashString = hash.base64EncodedStringWithOptions(NSDataBase64EncodingOptions([]))
            hashResult.destroy()
            return hashString
        }
    }

最佳答案

终于成功了:)

这是我的代码,其中列出了 Azure 存储帐户中的所有表:

//
//  main.swift
//  Azure Storage REST Helper
//
//  Created by Gaurav Mantri on 1/2/16.
//

import Foundation
let accountName = "{account-name}"
let urlString = "https://{account-name}.table.core.windows.net/Tables"
let storageUrl = NSURL(string: urlString)
let request = NSMutableURLRequest(URL: storageUrl!)
let currentDate = NSDate()
let httpFormatter = NSDateFormatter()
httpFormatter.timeZone = NSTimeZone(abbreviation: "GMT")
httpFormatter.dateFormat = "EEE',' dd MMM yyyy HH':'mm':'ss z"
let httpTime = httpFormatter.stringFromDate(currentDate)
print(httpTime)

let signingString = "GET\n\n\n\(httpTime)\n/{account-name}/Tables"
print(signingString)
let keyString = "{account-key}"
let keyData = NSData(base64EncodedString: keyString, options: NSDataBase64DecodingOptions.IgnoreUnknownCharacters)!

let signingData = signingString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
let length:Int = Int(CC_SHA256_DIGEST_LENGTH)
let hashResult = UnsafeMutablePointer<CUnsignedChar>.alloc(length)
CCHmac(CCHmacAlgorithm(kCCHmacAlgSHA256), keyData.bytes, Int(keyData.length), signingData.bytes, Int(signingData.length), hashResult)
print(hashResult)
let hash = NSData(bytes: hashResult, length: Int(CC_SHA256_DIGEST_LENGTH))
let hashString = hash.base64EncodedStringWithOptions(NSDataBase64EncodingOptions([]))
hashResult.destroy()

print(hashString)

request.setValue("SharedKey {account-name}:\(hashString)", forHTTPHeaderField: "Authorization")
request.setValue("0", forHTTPHeaderField: "Content-Length")

request.setValue(httpTime, forHTTPHeaderField: "x-ms-date")
request.setValue("", forHTTPHeaderField: "Date")

request.HTTPMethod = "GET"
print("comes here")
NSURLSession.sharedSession().dataTaskWithRequest(request, completionHandler: { (data, response, error) in
    if let data = data {
        let datastring = NSString(data:data, encoding:NSUTF8StringEncoding)
        print( datastring! )
        print("comes here 1")
        //print(response)

    } else {
        print("comes here 2")
        print( error )

    }
}).resume()

我做了一些事情:

  • 我没有使用 UTF8 编码来获取 keyData,而是使用 base64Encoding 创建了 NSData
  • 我删除了 Content-Type header ,因此结果以 XML 形式返回。如果您想返回 JSON 格式的数据,请指定 Accept header ,而不是 Content-Type header 。
  • 您使用 SharedKey 方案创建签名,但在 Authorization header 中指定了 SharedKeyLite。我将其更改为 SharedKey

哦,请不要评判代码并随意编辑它。我知道这不是最好的代码:)

关于ios - 从 Swift 访问 Azure 表存储,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34561203/

相关文章:

ios - 根据行高在 UITableViewCell 中移动 UIImage

ios - 尝试合并 2 个 Audiokit 示例 : MicrophoneAnalysis and Recorder: crashes when I hit record

ios - 如何在 Collection View 中显示从图库中选择的多张图像?

ios - 如何在 Swift 中旋转 UIButton 和 UILabel 的文本?

java - 使用应用程序发送 HTTP 请求 - Android Studio

c# - 如何获取发起重定向的服务器IP

iphone - 在 iOS 中添加应用程序范围标题 View 的最佳实践

iOS:当前AVAudioPlayer的AudioUnit

swift - 在 UICollectionView 中重新加载数据

java - 来自服务器的字符串无法转换为 JSONObject?