NIFCLOUD-mbaas / UserCommunity

ニフクラ mobile backend ユーザーコミュニティ
https://mbaas.nifcloud.com/
81 stars 18 forks source link

REST API を使うための Signature がエラー #376

Closed treastrain closed 8 years ago

treastrain commented 8 years ago

先日、ニフティクラウドmobile backend を使用し始めました。 特にプッシュ配信のための REST API が使えるという部分に惹かれました。

Signature を取得し、REST API へ POST するために以下のような Swift のコードを書いたのですが、 {"code":"E403002","error":"Unauthorized operations for signature."} のエラーで前に進むことが出来ません。 このユーザーコミュニティも読みましたが、いまいちよく分からず…と言ったところです。

間違いなど指摘して頂けませんか?

import Cocoa
import CryptoSwift

        let applicationKey = "アプリケーションキー"
        let clientKey = "クライアントキー"
        let method = "GET"
        let fqdn = "mb.api.cloud.nifty.com"
        let path = "/2013-09-01/classes/TestClass"
        let query = "where=%7B%22testKey%22%3A%22testValue%22%7D"
        let signatureMethod = "SignatureMethod=HmacSHA256"
        let signatureVersion = "SignatureVersion=2"

        let now = NSDate()
        let iso8601UTCFormatter = NSDateFormatter()
        iso8601UTCFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss'Z'"
        iso8601UTCFormatter.timeZone = NSTimeZone(forSecondsFromGMT: 0)
        let timestamp = iso8601UTCFormatter.stringFromDate(now)

        var signatureDataString = method + "\n"
        signatureDataString += fqdn + "\n"
        signatureDataString += path + "\n"
        signatureDataString += signatureMethod + "&"
        signatureDataString += signatureVersion + "&"
        signatureDataString += "X-NCMB-Application-Key=" + applicationKey + "&"
        signatureDataString += "X-NCMB-Timestamp=" + timestamp + "&"
        signatureDataString += query

        let clientKeyByte: [UInt8] = (clientKey.dataUsingEncoding(NSUTF8StringEncoding)?.arrayOfBytes())!
        let authenticator:Authenticator = Authenticator.HMAC(key: clientKeyByte, variant: HMAC.Variant.sha256)
        let message = signatureDataString.dataUsingEncoding(NSUTF8StringEncoding)
        let signatureDataByte = try! authenticator.authenticate((message?.arrayOfBytes())!)

        let signatureData = NSData(bytes: signatureDataByte)
        let signature = signatureData.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.EncodingEndLineWithLineFeed)

        let config = NSURLSessionConfiguration.defaultSessionConfiguration()
        let session = NSURLSession(configuration: config)

        let url = NSURL(string: "https://mb.api.cloud.nifty.com/2013-09-01/push")
        let params:[String: AnyObject] = [
            "immediateDeliveryFlag":true,
            "target":[
                "ios"
            ],
            "message":"メッセージ"
        ]
        let req = NSMutableURLRequest(URL: url!)
        req.HTTPMethod = "POST"
        req.setValue(applicationKey, forHTTPHeaderField: "X-NCMB-Application-Key")
        req.setValue(timestamp, forHTTPHeaderField: "X-NCMB-Timestamp")
        req.setValue(signature, forHTTPHeaderField: "X-NCMB-Signature")
        req.setValue("application/json", forHTTPHeaderField: "Content-Type")

        req.HTTPBody = try! NSJSONSerialization.dataWithJSONObject(params, options: NSJSONWritingOptions())

        let task = session.dataTaskWithRequest(req, completionHandler: {
            (data, resp, err) in
            print(String(data: data!, encoding: NSUTF8StringEncoding)!)
            // {"code":"E403002","error":"Unauthorized operations for signature."}
        })
        task.resume()

このコードは以下の Web ページを参考にしました。

goofmint commented 8 years ago

queryが

"immediateDeliveryFlag":true,
            "target":[
                "ios"
            ],
            "message":"メッセージ"
        ]

相当になっていないのが原因かなと。query=paramsです。

treastrain commented 8 years ago

@moongift さん コメントありがとうございます。

NSMutableURLRequest の HTTPBody に let params:[String: AnyObject] = ["immediateDeliveryFlag":true,"target":["ios"],"message":"メッセージ"] を指定していますが、この方法だとクエリになっていないのでしょうか。

すみません。初心者なものでいまいちよく分かっていません。

goofmint commented 8 years ago

私が気になったのは、

let query = "where=%7B%22testKey%22%3A%22testValue%22%7D"

です。このqueryもparamsと同じものになっている必要があります。

treastrain commented 8 years ago

@moongift さん

let method = "GET"
let fqdn = "mb.api.cloud.nifty.com"
let path = "/2013-09-01/classes/TestClass"

この部分に間違いはありませんか。

goofmint commented 8 years ago

いえ、パスも違いますね。前半はTestClassというのが対象で、後半では /push になっています。

https://github.com/NIFTYCloud-mbaas/ncmb_ios/blob/master/NCMB/NCMBURLConnection/NCMBURLConnection.m#L183

Objective-Cですが、SDKのコードが参考になるかと。

treastrain commented 8 years ago

@moongift さん 何度もありがとうございます。 Objective-C のコードはすでに拝見していました。

何度もドキュメントと @moongift さんからのアドバイスを見直し、正しくプッシュ通知登録の REST API を使えるようになりました! 本当にありがとうございました!

treastrain commented 8 years ago

後からこの Issue をチェックする方のために追記しておきますが、 @moongift さんがおっしゃっていた 「このqueryもparamsと同じものになっている必要があります。」 というのはこの場合には当てはまりません。

そもそもプッシュ通知登録 API にクエリは必要ありませんので、 クエリは無し、ということになります。