2016-01-01 3 views
1

Я хочу получить доступ к хранилищу таблиц azure из Swift. Инструкция для создания заголовка является here Однако, я пытался построить запрос, но не может заставить его работать:Доступ к хранилищу таблиц Azure от Swift

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() 

После правильного ответа ниже, я сделал пристройку к String, поэтому 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 
     } 
    } 
+0

Я не разработчик iOS (поэтому я не знал бы, как вы это сделаете), но я заметил, что вы конвертируете строку ключа учетной записи в объект NSData, используя Кодирование UTF8. Обратите внимание, что ключ является строкой, кодированной Base64. В мире .Net мы делаем что-то вроде 'Convert.FromBase64String (key)' для получения массива байтов. Можете ли вы попробовать сделать что-то подобное в своем коде? –

+0

Привет, Это происходит здесь let hashString = hash.base64EncodedStringWithOptions (NSDataBase64EncodingOptions ([])), поэтому я не думаю, что это проблема. – user1700737

+0

Разве вы не должны делать то же самое здесь ... 'let keyData = keyString.dataUsingEncoding ...'? Я знаю, что в .Net, если мы получаем массив байтов с использованием UTF8, мы всегда получаем ошибку. –

ответ

2

Наконец получил это работает :)

Вот мой код, который перечисляет все таблицы в учетной записи Azure Storage:

// 
// 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, я создал NSDatabase64Encoding использованием.
  • Я избавился от заголовка Content-Type, поэтому результат возвращается в XML. Если вы хотите вернуть данные в формате JSON, укажите заголовок Accept вместо Content-Type.
  • Вы создавали подпись, используя схему SharedKey, но вы указали SharedKeyLite в заголовке Authorization. Я изменил это на SharedKey.

О, и, пожалуйста, не судите о коде и не стесняйтесь его редактировать. Я знаю, что это не лучший код :)

+0

GREAT, большое спасибо за вашу помощь. – user1700737

+0

Пожалуйста, взгляните на 3 балла в моем ответе. Это вызвало ошибку. Я просто их исправил. –

+0

Да, я видел их сейчас. Сожалею. Но вы очень помогли, и первый в Интернете решил это :-) Я видел немало сообщений с той же проблемой. – user1700737

Смежные вопросы