Uber 在 ios Swift 中提供了无效的 OAuth 2.0 凭据

Posted

技术标签:

【中文标题】Uber 在 ios Swift 中提供了无效的 OAuth 2.0 凭据【英文标题】:Uber Invalid OAuth 2.0 credentials provided Uber Authentication In ios Swift 【发布时间】:2015-07-05 21:02:02 【问题描述】:

我正在我的 ios (Swift) 应用程序中实现 Uber's Request Endpoint。 Request API/Endpoint 需要应用用户认证,这里是doc。

为此,我正在使用Oauth2.0 library

我做的是

    借助给定的安装说明成功地将库集成到我的项目 (xCode) 中。

    在我的 AppDelegate 中

    let uber_OAuth_Settings = [
    "client_id": "XXXXXXX9vtKzobvXXXXXX",
    "client_secret": "EXXXXXXXXyFUNCa_Wez6AXXXXXXXnrXtxus",
    "authorize_uri": "https://login.uber.com/oauth/authorize",
    "token_uri": "https://login.uber.com/oauth/token",
    "redirect_uris": ["jamesappv2://oauth/callback"],   // don't forget to register this scheme
    ] as OAuth2JSON
    

    var oauth:OAuth2CodeGrant!

    在我的 Appdelegate 方法didFinishLaunchingWithOptions

     oauth = OAuth2CodeGrant(settings: uber_OAuth_Settings)
    oauth.viewTitle = "Uber Login Service"      // optional
    oauth.verbose = true // For Logs
    

    别忘了注册 url scheme 即 ("redirect_uris": ["jamesappv2://oauth/callback"])

转到您应用的目标 -> 信息选项卡 -> 网址类型 -> 单击 (+),附加图片

    在 AppDelegate 中添加下面给出的方法并处理回调 URL

    func application(application: UIApplication,
    openURL url: NSURL,
    sourceApplication: String?,
    annotation: AnyObject?) -> Bool 
        // you should probably first check if this is your URL being opened
    
       var splitUrl = url.absoluteString!.componentsSeparatedByString(":")
    
        if splitUrl[0] == ("jamesappv2") 
    
            oauth.handleRedirectURL(url)
        
    
        return true
    
    

    现在在我的 viewController 中,我在 myBtnClick 上这样做了

    let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
    
    let url = appDelegate.oauth.authorizeURL()
    UIApplication.sharedApplication().openURL(url)        
    appDelegate.oauth.onAuthorize =  parameters in
        println("Did authorize with parameters: \(parameters)")
    
        self.navigationController?.pushViewController(self.PersonalDriverUber_VC, animated: true)
    //On Authorization Goto another ViewController using pushViewController of navigationcontroller Method
    
    
    appDelegate.oauth.onFailure =  error in        // `error` is nil on cancel
        if nil != error 
            println("Authorization went wrong: \(error!.localizedDescription)")
        
    
    

这是我的调试日志,我得到了有效的响应:

    OAuth2: Handling redirect URL jamesappv2://oauth/callback?state=4B0EB812&code=0sXXXXXXTX7yEbS1XXXXXHuw
OAuth2: Successfully validated redirect URL
OAuth2: Authorizing against https://login.uber.com/oauth/token?state=38158941&grant_type=authorization_code&code=0sXXXXXXXX1jxTrdFQT9Huw&client_secret=EIXXXXXXXNCa_Wez6XXXXXw0BlnrXtxus&client_id=fXXXXXXXy2LOUo9vtKXXXXXQ1nUDO&redirect_uri=jamesappv2%3A%2F%2Foauth%2Fcallback
OAuth2: Exchanging code 0swNXXXXX7yXXXXXXdFQT9Huw with redirect jamesappv2://oauth/callback for token at Optional("https://login.uber.com/oauth/token")
OAuth2: Did receive access token: Dfq3XXXXXXuWgpaqFXXXXXXXgXW, refresh token: EmStT7FEXHRMlS8odPzs1nsha0ObjK
Did authorize with parameters: [token_type: Bearer, expires_in: 2592000, access_token: XXXXXXOZuWgXXXXXXXXuJYOmgXW, refresh_token: EXXXXXHRMlS8oXXXXXXXa0ObjK, scope: profile, last_authenticated: 1430121470]

通知我正在获取有效的 access_token

我卡住了

根据DOCs 在 STEP4 中所说的 *USE BEARER TOKEN

将响应中返回的 access_token 传递到 Authorization 标头中,类型为 Bearer,以代表用户发出请求。*

curl -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' 'https://api.uber.com/v1/products?latitude=37.7759792&longitude=-122.41823'

我不明白这一点。我应该如何使用 Bearer 类型传递 Header 中的 access_token?我已经完成了如下操作

func callRequestAPI(url:String)

    let request = appDelegate.oauth.request(forURL: NSURL(string:url)!)



    request.HTTPMethod = "POST"


    let postString = "product_id="+selectedUberProductId+"&start_latitude="+start_lat+"&start_longitude="+start_lng+"&end_latitude="+end_lat+"&end_longitude="+end_lng

    println(postString)


    let tempData: NSData = appDelegate.oauth.accessToken.dataUsingEncoding(NSUTF8StringEncoding)!
    let base64LoginString = tempData.base64EncodedStringWithOptions(nil)

    request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
    request.addValue("application/json", forHTTPHeaderField: "Content-Type")
    request.addValue("application/json", forHTTPHeaderField: "Accept")




   request.setValue("Bearer \(base64LoginString)", forHTTPHeaderField: "Authorization")

    let session = NSURLSession.sharedSession()

    let task = session.dataTaskWithRequest(request)  data, response, error in


        if error != nil 
            println("error=\(error)")
            return
        

        println("response = \(response)")

        let responseString = NSString(data: data, encoding: NSUTF8StringEncoding)
        println("responseString = \(responseString)")

    
    task.resume()

但我收到以下回复

response = <NSHTTPURLResponse: 0x1a284b50>  URL: https://sandbox-api.uber.com/v1/requests   status code: 401, headers 
"Content-Length" = 75;
"Content-Type" = "application/json";
Date = "Mon, 27 Apr 2015 10:22:01 GMT";
Server = nginx;
"Strict-Transport-Security" = "max-age=31536000; includeSubDomains; preload";
"x-uber-app" = "uberex-sandbox";
"x-xss-protection" = "1; mode=block";
 
responseString = Optional("message":"Invalid OAuth 2.0 credentials provided.","code":"unauthorized")

【问题讨论】:

看看 charles 的请求,也许你发现了错误。 对不起,我没有得到你。 @QadirHussain Charles 是一个网络监控工具。它可以很容易地查看从模拟器和服务器来回发送的内容。 @Chackle 感谢您的许可 【参考方案1】:

要使用令牌,只需按照OAuth2 库中说明的第 5 步操作,就像您在开始尝试自己第二次签名之前所做的那样。请求已经签名并设置了 Bearer 令牌,您无需做任何事情:

let url = NSURL(string: "https://api.uber.com/v1/products?latitude=37.7759792&longitude=-122.41823")
let req = appDelegate.oauth.request(forURL: url)

// customize your request, if needed. E.g. for POST:
req.HTTPMethod = "POST"

// send the request
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(req)  data, response, error in
    if nil != error 
        // something went wrong
    
    else 
        // check the response and the data
        // you have just received data with an OAuth2-signed request!
    

task.resume()

【讨论】:

是的,但我必须发送一个帖子请求。当我为驱动程序请求端点发送 POST 请求时,上面给出的代码返回给我 "message":"Invalid OAuth 2.0 credentials provided.","code":"unauthorized" :( 我也有同样的问题。如何发送 OAuth 2.0 凭据?我已收到访问令牌,但如何使用? 如果您执行appDelegate.oauth.request(forURL: url),则凭据已包含在请求中。我更新了示例,向您展示了您可以在哪里自定义您的请求。【参考方案2】:

我终于做到了:)

我改变了下面的方法,它工作了

func callRequestAPI(url:String)

    var configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
    var session = NSURLSession(configuration: configuration)

    let params:[String: AnyObject] = [
        "product_id" : selectedUberProductId,
        "start_latitude" : start_lat,
        "start_longitude" : start_lng,
        "end_latitude" : end_lat,
        "end_longitude" : end_lng]



    let request = appDelegate.oauth.request(forURL: NSURL(string:url)!)
    request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
    request.HTTPMethod = "POST"
    var err: NSError?
    request.HTTPBody = NSJSONSerialization.dataWithJSONObject(params, options: NSJSONWritingOptions.allZeros, error: &err)

    let task = session.dataTaskWithRequest(request) 
        data, response, error in

        if let httpResponse = response as? NSHTTPURLResponse 
            if httpResponse.statusCode != 202 
                println("response was not 202: \(response)")

                return
            
        
        if (error != nil) 
            println("error submitting request: \(error)")
            return
        

        // handle the data of the successful response here
        var result = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.allZeros, error: nil) as! NSDictionary


        println(result)

        if let request_id: String = result["request_id"] as? String

            println(request_id)
        

        if let driver: String = result["driver"] as? String

            println(driver)
        

        if let eta: Int = result["eta"] as? Int

            println(eta)
        

        if let location: String = result["location"] as? String

            println(location)
        


        if let status: String = result["status"] as? String

            println(status)
        


        if let surge_multiplier: Int = result["surge_multiplier"] as? Int

            println(surge_multiplier)
        

        if let vehicle: String = result["vehicle"] as? String

            println(vehicle)
        

    

    task.resume()


这是我得到的响应,我上面的方法中也给出了解析


  driver = "<null>";
  eta = 15;
  location = "<null>";
  "request_id" = "ea39493d-b718-429f-8710-00a34dcdaa93";
  status = processing;
  "surge_multiplier" = 1;
  vehicle = "<null>";

享受

【讨论】:

你对这个方法做了哪些改变? @Jagdeep 请查看我的问题中的 callRequestAPI() 并与我的答案中的相同内容进行比较。你看到了差异:) 我可以快速识别出两个不同之处,即 param post 和 header 内容。对吗? 您是如何通过您的应用授权用户的 uber 帐户的?我正在尝试找到如何完成此操作的示例,但在任何地方都找不到。【参考方案3】:

已针对 Swift 2 进行了更新。我为 oauth 使用了与 Qadir 在他的问题中描述的相同的设置和库。我更新了他在 Swift 2 中工作的请求。希望这对其他人有所帮助。

超级请求:

    let params:[String:AnyObject] = [
        "product_id" : uberProduct,
        "start_latitude" : userLat,
        "start_longitude" : userLng,
        "end_latitude" : barLat,
        "end_longitude" : barLng]

    let urlPath = "https://sandbox-api.uber.com/v1/requests"
    let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
    var configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
    var session = NSURLSession(configuration: configuration)

    guard let endpoint = NSURL(string: urlPath) else  print("Error creating endpoint");return 

    let request = appDelegate.oauth.request(forURL: NSURL(string:urlPath)!)
    request.setValue("application/json; charset=utf-8", forHTTPHeaderField:"Content-Type")

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

    request.HTTPMethod = "POST"

    print("Prepare to make request -> \(request)")

    let task = NSURLSession.sharedSession().dataTaskWithRequest(request) data, response, error in
        if error != nil
            print("Error -> \(error)")
            return
        

        do 
            let result = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers)

            print("Result -> \(result)")

         catch 
            print("Error -> \(error)")
        
    

    task.resume()

返回:

Result -> Optional(["driver": <null>, "request_id": 5834384c-7283-4fe6-88a7-e74150c6ab30, "surge_multiplier": 1, "location": <null>, "vehicle": <null>, "status": processing, "eta": <null>])

【讨论】:

以上是关于Uber 在 ios Swift 中提供了无效的 OAuth 2.0 凭据的主要内容,如果未能解决你的问题,请参考以下文章

“无效的 Swift 支持”在 Xamarin.iOS 中使用本机 Swift 库

Uber 错误 请求的范围无效

Uber使用Swift重写APP的踩坑经历及解决方案(转载)

无效的 JSON 需要 Swift iOS

无效的 Swift Support-ERROR IOS APP PUBLISHING?

您能否在应用程序提交状态“无效二进制”中出现错误“无效的 Swift 支持”和“缺少所需的图标文件”提供帮助?