【问题标题】:OAuth2, Swift 3, InstagramOAuth2、Swift 3、Instagram
【发布时间】:2016-10-27 14:05:12
【问题描述】:

IG 似乎发生了很多变化。许多 OAuth2 存储库,似乎都有错误,或者真的不容易转换为 Swift3。想知道是否有人有迁移到 Swift3 并处理 Instagram 最新变化的解决方案?

欢迎提供解决方案。 OAuth2 的实现似乎是最复杂的事情之一。令 IG 没有提供他们自己的关于如何使用 iOS 执行此操作的示例文档感到惊讶。他们只有基于 Web 的解决方案的文档。

也许那里正在酝酿什么?他们有数以亿计的编码员。但就目前而言,正在寻找一个(我敢说?)简单的解决方案。

感谢一百万。 :-)

【问题讨论】:

  • 我在 Swift 3 中使用 OAuth2 来登录 facebook。我认为这很相似...如果您愿意...我可以为您发帖。
  • 是的,FB 很酷,但与 Instagram 不同。 Instagram 是我需要解决的棘手问题。回调 URL 是一个难题。

标签: ios swift swift3 instagram oauth2


【解决方案1】:

对于 Swift 3:

更新:2017 年 4 月 17 日:由于依赖关系损坏,Pods 的安装不再有效。因此,我已经翻录了所需的内容并使用桥接头创建了一个 new Github project 并将所有需要的文件存储在项目中。如果您克隆或下载 github 项目,您将立即能够登录 Instagram。

要在您的项目中使用这些文件,只需将所有文件从 SimpleAuth 文件夹拖放到您的项目中,确保标记copy item if needed

您还需要在 Instagram 开发者控制台中禁用 Disable implicit oAuth

然后,您可以将我的代码从桥接头复制/粘贴到您的或使用我的。在目标的构建设置中设置桥接头。

其他一切都和以前一样:

我有一个 Instagram 帐户的结构:

struct InstagramUser {

    var token: String = ""
    var uid: String = ""
    var bio: String = ""
    var followed_by: String = ""
    var follows: String = ""
    var media: String = ""
    var username: String = ""
    var image: String = ""
}

接收令牌的函数:

typealias JSONDictionary = [String:Any]
var user: InstagramUser?
let INSTAGRAM_CLIENT_ID = "16ee14XXXXXXXXXXXXXXXXXXXXXXXXX"
let INSTAGRAM_REDIRECT_URI = "http://www.davidseek.com/just_a_made_up_dummy_url" //just important, that it matches your developer account uri at Instagram

extension ViewController {

    func connectInstagram() {

        let auth: NSMutableDictionary = ["client_id": INSTAGRAM_CLIENT_ID,
                                         SimpleAuthRedirectURIKey: INSTAGRAM_REDIRECT_URI]

        SimpleAuth.configuration()["instagram"] = auth            
        SimpleAuth.authorize("instagram", options: [:]) { (result: Any?, error: Error?) -> Void in

            if let result = result as? JSONDictionary  {

                var token = ""
                var uid = ""
                var bio = "" 
                var followed_by = ""
                var follows = ""
                var media = ""
                var username = ""
                var image = ""

                token = (result["credentials"] as! JSONDictionary)["token"] as! String
                uid = result["uid"] as! String

                if let extra = result["extra"] as? JSONDictionary,
                    let rawInfo = extra ["raw_info"] as? JSONDictionary,
                    let data = rawInfo["data"] as? JSONDictionary {

                    bio = data["bio"] as! String

                    if let counts = data["counts"] as? JSONDictionary {
                        followed_by = String(describing: counts["followed_by"]!)
                        follows = String(describing: counts["follows"]!)
                        media = String(describing: counts["media"]!)
                    }
                }

                if let userInfo = result["user_info"] as? JSONDictionary {
                    username = userInfo["username"] as! String
                    image = userInfo["image"] as! String
                }

                self.user = InstagramUser(token: token, uid: uid, bio: bio, followed_by: followed_by, follows: follows, media: media, username: username, image: image)


            } else {
                // this handles if user aborts or the API has a problem like server issue
                let alert = UIAlertController(title: "Error!", message: nil, preferredStyle: UIAlertControllerStyle.alert)
                alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
                self.present(alert, animated: true, completion: nil)
            }

            if error != nil {
                print("Error during SimpleAuth.authorize: \(error)")
            }
        }
    }
}

Instagram 还说:

重要

即使我们的访问令牌没有指定过期时间,您的 应用程序应处理用户撤销访问权限或 Instagram 会在一段时间后过期令牌。如果令牌是 不再有效,API 响应将包含 “error_type=OAuthAccessTokenException”。在这种情况下,您需要 重新认证用户以获得新的有效令牌。换一种说法: 不要假设您的 access_token 永远有效。

所以处理收到OAuthAccessTokenException的情况

【讨论】:

  • 嗨,大卫,感谢您提供的信息。我真的在寻找 Swift3 版本。 SimpleAuth 不能用最新的 xcode 编译。
  • 老兄。我在 swift 3 项目中将它与最新的 xcode 一起使用。如果我不这样做,我就不会花 30 分钟的时间来写这个答案
  • 所有你需要做的就是将simpleauth的依赖编译成swift 3...在一秒钟内为你上传一个示例项目...
  • 完美解决方案。非常感谢您的回答。
  • @DavidSeek 您应该为这个答案获得 1000 票赞成。非常感谢!
【解决方案2】:

以下代码我用于 facebook 和 google+,我认为它也适用于 Instagram,也许会进行一些调整。

import UIKit

class Signup: UIViewController, UIWebViewDelegate {
    let GOOGLE_ID = "xxxxxx.apps.googleusercontent.com"
    let GOOGLE_SECRET = "xxxxxxx";
    let GOOGLE_REDIRECT_URI="http://yourdomain.com/api/account/googlecallback"
    let GOOGLE_TOKEN_URL = "https://accounts.google.com/o/oauth2/token";
    let GOOGLE_OAUTH_URL = "https://accounts.google.com/o/oauth2/auth";
    let GOOGLE_OAUTH_SCOPE = "profile email";
    let GOOGLE_GET_PROFILE = "https://www.googleapis.com/userinfo/v2/me";
    let FACEBOOK_ID = "xxxxx";
    let FACEBOOK_REDIRECT_URI = "http://yourdomain.com/api/account/facebookcallback";
    let FACEBOOK_OAUTH_URL = "https://www.facebook.com/dialog/oauth?client_id=";
    let FACEBOOK_OAUTH_SCOPE = "public_profile,email"
    let FACEBOOK_GET_PROFILE = "https://graph.facebook.com/me?access_token="
    var currentURL: String = ""
    var queryString: String = ""
    var receivedToken: String = ""
    var authCode: String = ""
    var authComplete = false
    var webV:UIWebView = UIWebView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height))
    @IBAction func google(_ sender: AnyObject) {
        AppVars.Provider = "Google"
        webV.delegate = self
        let url = GOOGLE_OAUTH_URL + "?redirect_uri=" + GOOGLE_REDIRECT_URI + "&response_type=code&client_id=" + GOOGLE_ID + "&scope=" + GOOGLE_OAUTH_SCOPE
        let urlString :String =  url.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)!
        webV.loadRequest(URLRequest(url: URL(string:urlString)!))
        self.view.addSubview(webV)
    }

    @IBAction func facebook(_ sender: AnyObject) {
        AppVars.Provider = "Facebook"
        webV.delegate = self
        let url = FACEBOOK_OAUTH_URL + FACEBOOK_ID + "&redirect_uri=" + FACEBOOK_REDIRECT_URI + "&scope=" + FACEBOOK_OAUTH_SCOPE + "&display=popup&response_type=token"
        let urlString :String =  url.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)!
        webV.loadRequest(URLRequest(url: URL(string:urlString)!))
        self.view.addSubview(webV)
    }
    func webView(_ webView: UIWebView, didFailLoadWithError error: Error) {
         self.showAlert(self, message: "Internet is not working")
    }

    func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebViewNavigationType) -> Bool {
        return true;
    }

    func webViewDidStartLoad(_ webView: UIWebView) {
    }

    func webViewDidFinishLoad(_ webView: UIWebView) {
        currentURL = (webView.request?.url!.absoluteString)!
        if AppVars.Provider == "Google" {
           googleSignup((webView.request?.url!)!)
        } else {
           facebookSignup((webView.request?.url!)!)
        }
    }

    func googleSignup (_ returnCode: URL) {
            let url = String(currentURL)
            if (url?.range(of: "?code=") != nil && authComplete != true) {
                authCode =  getQueryItemValueForKey("code", url: returnCode)!
                authComplete = true
                let paramString = "code=" + authCode + "&client_id=" + GOOGLE_ID + "&client_secret=" +
                    GOOGLE_SECRET + "&redirect_uri=" + GOOGLE_REDIRECT_URI + "&grant_type=authorization_code"
                self.requestServer(urlSource: GOOGLE_TOKEN_URL, params: paramString, requestType: "POST") { (dataResult, errorResult) -> () in
                    if errorResult != nil {
                         self.showAlert(self, message: "Internet is not working")
                    } else {
                        let dataString:NSString = NSString(data: dataResult as! Data, encoding: String.Encoding.utf8.rawValue)!
                        let dataResult2 = dataString.data(using: String.Encoding.utf8.rawValue, allowLossyConversion: false)!
                        do {
                            let jsonDict = try JSONSerialization.jsonObject(with: dataResult2, options: .allowFragments)  as! [String:Any]
                            if let token = jsonDict["access_token"] as? String {
                                self.requestServerSignup(self.GOOGLE_GET_PROFILE, param: token, requestType: "GET") { (dataResult, errorResult) -> () in
                                    if errorResult != nil {
                                         self.showAlert(self, message: "Internet is not working")
                                    } else {
                                        let dataString:NSString = NSString(data: dataResult as! Data, encoding: String.Encoding.utf8.rawValue)!
                                        let dataResult2 = dataString.data(using: String.Encoding.utf8.rawValue, allowLossyConversion: false)!
                                        do {
                                            let jsonDict = try JSONSerialization.jsonObject(with: dataResult2, options: .allowFragments) as! [String:Any]
                                            if let name = jsonDict["name"] as? String {
                                                AppVars.NameLogin = name
                                                AppVars.PictureLogin = jsonDict["picture"] as! String
                                                AppVars.EmailLogin = jsonDict["email"] as! String
                                                self.performSegue(withIdentifier: "externalLoginSegue", sender: self)
                                                // show picture, email and name for checking profile
                                            }
                                        } catch  {
                                             self.showAlert(self, message: "Internet is not working")
                                        }
                                    }
                                }
                            }

                        } catch  {
                             self.showAlert(self, message: "Internet is not working")
                        }
                    }
                }
                self.webV.removeFromSuperview()
            }

    }

    func facebookSignup(_ returnCode: URL) {
            let url = String(currentURL)
            if (url?.range(of: "access_token=") != nil && authComplete != true) {
                let url2: String = returnCode.absoluteString.replacingOccurrences(of: "#access_token", with: "access_token")
                let url3: URL = URL(string: url2)!
                authCode =  getQueryItemValueForKey("access_token", url: (url3))!
                authComplete = true
                let paramString = "code=" + authCode + "&client_id=" + GOOGLE_ID + "&client_secret=" +
                    GOOGLE_SECRET + "&redirect_uri=" + GOOGLE_REDIRECT_URI + "&grant_type=authorization_code"
                self.requestServer(urlSource: self.FACEBOOK_GET_PROFILE + authCode + "&fields=name,picture,email", params: paramString, requestType: "GET") { (dataResult, errorResult) -> () in
                    if errorResult != nil {
                         self.showAlert(self, message: "Internet is not working")
                    } else {
                        let dataString:NSString = NSString(data: dataResult as! Data, encoding: String.Encoding.utf8.rawValue)!
                        let dataResult2 = dataString.data(using: String.Encoding.utf8.rawValue, allowLossyConversion: false)!
                        do {
                            let jsonDict = try JSONSerialization.jsonObject(with: dataResult2, options: .allowFragments) as! [String:Any]
                            if let name = jsonDict["name"] as? String {
                                AppVars.NameLogin = name
                                if let picture = jsonDict["picture"] as? [String:Any] {
                                    if let dataPicture = picture["data"] as? [String:Any] {
                                        if let url = dataPicture["url"] as? String {
                                            AppVars.PictureLogin = url
                                        }
                                    }
                                }
                                AppVars.EmailLogin = jsonDict["email"] as! String
                                self.performSegue(withIdentifier: "externalLoginSegue", sender: self)
                                // show picture, email and name for checking profile
                            }

                        } catch  {
                             self.showAlert(self, message: "Internet is not working")
                        }
                    }
                }
                self.webV.removeFromSuperview()
            }

    }

    override func viewDidLoad() {
        super.viewDidLoad()
    }


    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }


    func getQueryItemValueForKey(_ key: String, url: URL) -> String? {
        guard let components = URLComponents(url: url, resolvingAgainstBaseURL: false) else {
            return nil
        }
        guard let queryItems = components.queryItems else { return nil }
        return queryItems.filter {
            $0.name == key
            }.first?.value
    }

   func requestServer(urlSource:String, params:String, requestType:String, result:@escaping (_ dataResult:NSData?, _ errorResult:NSError?) -> ()) {
        let url: URL = URL(string: urlSource)!
        var request = URLRequest(url:url)
        request.httpMethod = requestType
        request.setValue("application/x-www-form-urlencoded; charset=utf-8", forHTTPHeaderField: "Content-Type")
        if params.characters.count > 0 {
            request.httpBody = params.data(using: String.Encoding.utf8)
        }
        let session = URLSession.shared
        session.dataTask(with: request) { (data, response, error) -> Void in
            DispatchQueue.main.async(execute: { () -> Void in
                if error == nil {
                    result(data as NSData?, nil)
                } else {
                    result(nil, error as NSError?)
                }
            })
        }.resume()
    }

}

【讨论】:

  • 您好,谢谢您的信息。 IG 与 Google 或 FB 有点不同。一个有趣的返回类型,以及令牌与代码的返回值。还需要有一个Swift3的解决方案。
猜你喜欢
  • 1970-01-01
  • 2017-05-04
  • 1970-01-01
  • 1970-01-01
  • 2021-11-26
  • 2015-12-18
  • 2015-05-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多