OAuth2,Swift 3,Instagram

IG中似乎有很多变化。 许多OAuth2回购,似乎都有错误,或者真的不容易转换成Swift3。 想知道是否有人有移动到Swift3的解决scheme,并与Instagram的最新变化工作?

最受欢迎的scheme OAuth2的实现似乎是其中比较复杂的事情之一。 惊讶IG没有提供他们自己的示例文档如何与iOS做到这一点。 他们只有基于Web的解决scheme的文档。

也许是在那里酿造的东西? 他们对工作人员有无数的编码员。 但就目前而言,在寻找一个(敢说我?)简单的解决scheme。

太感谢了。 🙂

对于Swift 3:

更新:2017年4月17日 :由于依赖关系中断,Pods安装不再有效。 因此,我翻录了所需的内容,并使用Bridging Header创build了一个新的Github项目,并在项目中存储了所有需要的文件。 如果你克隆或下载github项目,你将立即能够login到Instagram。

要在项目中使用这些文件,只需将SimpleAuth文件夹中的所有文件拖放到项目中,确保copy item if needed标记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”。 在这种情况下,您将需要重新validation用户以获取新的有效令牌。 换句话说:不要以为你的access_token永远有效。

所以处理接收OAuthAccessTokenException

此代码下面我使用的Facebook和谷歌+,我认为它也适用于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() } }