如何为oAuth

时间:2018-01-12 07:57:24

标签: ios swift oauth hmac hmacsha1

我正在使用下面的代码生成HMAC-SHA1签名,但在身份验证请求期间出现此错误:

  

“oauth_signature与期望值不匹配”

有谁能告诉我如何生成正确的签名?我还检查了oAuthSwiftallHTTPHeaderFields以获取Tumblr,它适用于此代码。

Tumblr_oAuth-Bridging-Header.h
#import <CommonCrypto/CommonHMAC.h>

class ViewController: UIViewController {

    let consumerKey = "SpFweFQePdB1I6GnbX2TKCrnD8sObObExERLtw1RBcaEZPFV26"
    let consumerSecret = "HCLK7WnNuZM7ohCoSqNixNhCs2YmASfnL8tkYaQvuh9DEj05o3"
    let requestTokenUrl = "www.tumblr.com/oauth/request_token"
    let authorizeUrl = "https://www.tumblr.com/oauth/authorize"
    let accessTokenUrl = "https://www.tumblr.com/oauth/access_token"
    let oauthTokenSecret = ""

    @IBAction func login(_ sender: Any) {

        let oauth_timestamp = String(Int64(Date().timeIntervalSince1970))
        let oauth_nonce = generateNonce()//: CFString = CFUUIDCreateString(nil, uuid)

        let parameters =  ["oauth_timestamp": "\(oauth_timestamp)", "oauth_callback": "oauth-swift://oauth-callback/tumblr", "oauth_signature_method": "HMAC-SHA1", "oauth_version": "1.0", "oauth_consumer_key": "SpFweFQePdB1I6GnbX2TKCrnD8sObObExERLtw1RBcaEZPFV26", "oauth_nonce": "\(oauth_nonce)"]

        let url = URL(string:"https://www.tumblr.com/oauth/request_token")
        let method = "POST"

        let encodedTokenSecret = self.oauthTokenSecret.urlEncoded
        let encodedConsumerSecret = self.consumerSecret.urlEncoded

        let signingKey = "\(encodedConsumerSecret)&\(encodedTokenSecret)"
        print(parameters)
        var parameterComponents = parameters.urlEncodedQuery.components(separatedBy: "&")
        parameterComponents.sort {
            let p0 = $0.components(separatedBy: "=")
            let p1 = $1.components(separatedBy: "=")
            if p0.first == p1.first { return p0.last ?? "" < p1.last ?? "" }
            return p0.first ?? "" < p1.first ?? ""
        }

        let parameterString = parameterComponents.joined(separator: "&")
        let encodedParameterString = parameterString.urlEncoded
        let encodedURL = url?.absoluteString.urlEncoded

        let signatureBaseString = "\(method)&\(String(describing: encodedURL))&\(encodedParameterString)"

        let key = signingKey//.data(using: .utf8)!
        let msg = signatureBaseString//.data(using: .utf8)!

        let signature : String = msg.hmac(algorithm: HMACAlgorithm.SHA1, key: key)
        print("signature",signature)

        var request = URLRequest(url: URL(string: "https://www.tumblr.com/oauth/request_token")!)

        request.allHTTPHeaderFields = ["Authorization": "OAuth oauth_callback=\"oauth-swift%3A%2F%2Foauth-callback%2Ftumblr\", oauth_consumer_key=\"SpFweFQePdB1I6GnbX2TKCrnD8sObObExERLtw1RBcaEZPFV26\", oauth_nonce=\"\(oauth_nonce)\", oauth_signature=\"\(signature.urlEncoded)\", oauth_signature_method=\"HMAC-SHA1\", oauth_timestamp=\"\(oauth_timestamp)\", oauth_version=\"1.0\""]

        request.httpMethod = "POST"
        let task = URLSession.shared.dataTask(with: request) { data, response, error in
            guard let data = data, error == nil else {                                                 // check for fundamental networking error
                print("error=\(String(describing: error))")
                return
            }

            if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 {           // check for http errors
                print("statusCode should be 200, but is \(httpStatus.statusCode)")
                print("response = \(String(describing: response))")
            }

            let responseString = String(data: data, encoding: .utf8)
            print("responseString = \(String(describing: responseString))")
        }
        task.resume()
    }

    override func viewDidLoad() {
        super.viewDidLoad()

    }
}
public func generateNonce() -> String {
    let uuidString = UUID().uuidString
    return uuidString.substring(to: 8)
}
enum HMACAlgorithm {
    case MD5, SHA1, SHA224, SHA256, SHA384, SHA512

    func toCCHmacAlgorithm() -> 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)
    }

    func digestLength() -> Int {
        var result: CInt = 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: HMACAlgorithm, key: String) -> String {
        let cKey = key.cString(using: String.Encoding.utf8)
        let cData = self.cString(using: String.Encoding.utf8)
        var result = [CUnsignedChar](repeating: 0, count: Int(algorithm.digestLength()))
        CCHmac(algorithm.toCCHmacAlgorithm(), cKey!, strlen(cKey!), cData!, strlen(cData!), &result)
        let hmacData:NSData = NSData(bytes: result, length: (Int(algorithm.digestLength())))
        let hmacBase64 = hmacData.base64EncodedString(options: NSData.Base64EncodingOptions.lineLength76Characters)// Encoding76CharacterLineLength)
        return String(hmacBase64)
    }

    var urlEncoded: String {
        let customAllowedSet = CharacterSet(charactersIn: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~")
        return self.addingPercentEncoding(withAllowedCharacters: customAllowedSet)!
    }

    var urlQueryEncoded: String? {
        return self.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)
    }

    func substring(to offset: String.IndexDistance) -> String {
        let to = self.index(self.startIndex, offsetBy: offset)
        return String(self[..<to])
    }
}
extension Dictionary {

    var urlEncodedQuery: String {
        var parts = [String]()

        for (key, value) in self {
            let keyString = "\(key)".urlEncoded
            let valueString = "\(value)".urlEncoded
            let query = "\(keyString)=\(valueString)"
            parts.append(query)
        }

        return parts.joined(separator: "&")
    }

}

0 个答案:

没有答案