问题:在 iOS 应用程序中使用 GitHub 进行 OAuth 身份验证 - 它是如何工作的

我正在尝试了解在 IOS 应用程序中使用 GITHUB 的 oauth 身份验证如何工作。

我正在开发一个 IOS 应用程序并想使用 GITHUB 进行登录验证。

这是我的应用程序的流程。

  1. 用户注册 - 这是一个离线过程,发生在我的应用程序之外。当我为用户创建帐户时,我要求他们提供他们的 GITHUB 电子邮件地址。我将此电子邮件地址作为该用户的用户 ID 存储在我们的数据库中。

  2. 从 GITHUB 获取访问令牌 - 当用户打开我们的应用程序时,我们使用 webview 将他们定向到https://github.com/login/oauth/authorize。用户成功登录 GITHUB 帐户后,我使用https://github.com/login/oauth/access_token获取访问令牌。

  3. 使用访问令牌获取电子邮件地址 - 我正在使用https://api.github.com/user/emails使用我在步骤 2 中获得的访问令牌获取登录帐户的电子邮件地址。

4.验证电子邮件地址:我根据我的数据库验证我在步骤3中获得的电子邮件地址。如果 userid 存在,那么用户将能够在我们的应用程序上进行交易。

现在,在 GITHUB 验证控制返回到具有 GITHUB 的 webview 的视图控制器之后,出现了一个空白屏幕。如何将流程移动到下一个视图控制器?

这是我的视图控制器代码:

import UIKit
import WebKit

class Login: UIViewController, UIWebViewDelegate {

    @IBOutlet weak var webview: UIWebView!
    override func viewDidLoad() {
        super.viewDidLoad()

        let authURL = String(format: "%@?client_id=%@&redirect_uri=%@&scope=%@", arguments: [GITHUB.GITHUB_AUTHURL,GITHUB.GITHUB_CLIENT_ID,GITHUB.GITHUB_REDIRECT_URI,GITHUB.GITHUB_SCOPE])

        let urlRequest = URLRequest.init(url: URL.init(string: authURL)!)
        webview.loadRequest(urlRequest)
        webview.delegate = self
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

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

    func checkRequestForCallbackURL(request: URLRequest) -> Bool {
        //print("3. IN FUNCTION checkRequestForCallbackURL")

        let requestURLString = (request.url?.absoluteString)! as String
        //print("3. requestURLString=\(requestURLString)")

        if requestURLString.hasPrefix(GITHUB.GITHUB_REDIRECT_URI) {

            let range: Range<String.Index> = requestURLString.range(of: "?code=")!

            handleGithubCode(code: requestURLString.substring(from: range.upperBound))

            return false;
        }

        return true
    }

    func handleGithubCode(code: String) {

            let urlString = "https://github.com/login/oauth/access_token"
            if let tokenUrl = URL(string: urlString) {

                let req = NSMutableURLRequest(url: tokenUrl)
                req.httpMethod = "POST"
                req.addValue("application/json", forHTTPHeaderField: "Content-Type")
                req.addValue("application/json", forHTTPHeaderField: "Accept")

                let params = [
                    "client_id" : GITHUB.GITHUB_CLIENT_ID,
                    "client_secret" : GITHUB.GITHUB_CLIENTSECRET,
                    "code" : code
                ]

                req.httpBody = try? JSONSerialization.data(withJSONObject: params, options: [])
                let task = URLSession.shared.dataTask(with: req as URLRequest) { data, response, error in

                    if let data = data {
                        do {
                            if let content = try JSONSerialization.jsonObject(with: data, options: []) as? [String: AnyObject] {
                                if let accessToken = content["access_token"] as? String {
                                    self.getComposerToken(accessToken: accessToken)

                                }
                            }
                        } catch {}
                    }
                }
                task.resume()
            }
    }

    func getComposerToken(accessToken: String) {
        print("5. accessToken=\(accessToken)")

        let def = "NO_DATA"

        let composerUrl = "http://192.168.100.112/kubher/getAccessToken.php?token=\(accessToken)"
        guard let url = URL(string: composerUrl) else { return }

        URLSession.shared.dataTask(with: url) { (data, response, error) in
            if let response = response {
                //print(response)
            }

            if let data = data {
                do {
                    let json = try? JSONSerialization.jsonObject(with: data, options: [])

                    if let dict = json as? [String: Any],
                        let token = dict["accessToken"] {
                        print("Blockchain Token:\(token)")
                    }
                } catch {
                    print(error)
                }
            }
        }.resume()
  }
}

解答

移至下一个视图控制器取决于代码的体系结构。根据您的设计尝试以下代码。 opt 1:如果你需要回到之前的 ViewController,只需修改你的 getComposerToken 函数:

if let dict = json as? [String: Any], {
    let token = dict["accessToken"] {
    print("Blockchain Token:\(token)")
    dispatch_async(dispatch_get_main_queue()) {
        self.presentingViewController?.dismissViewControllerAnimated(true, completion: nil)
    }
    }
}

选择 2:另一方面,如果您在情节提要中将 Segue 用于下一个 viewController,请为您的 segue 命名(标识符),然后按照以下代码操作:

if let dict = json as? [String: Any], {
        let token = dict["accessToken"] {
        print("Blockchain Token:\(token)")
        dispatch_async(dispatch_get_main_queue()) {
            self.performSegue(withIdentifier: "YourSegueName", sender: token)
        }
      }
    }

此外,您必须重写 prepare 方法来传递数据

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "segueName" {
            let viewController = segue.destination as? YourViewController
            if let token = sender as? String {
                viewController?.token = token
            }
        }
    }
}

OPT 3:如果您在从情节提要创建后使用推送视图控制器,则必须在情节提要中为您的视图控制器提供一个标识符,然后您可以使用实例化它并使用以下方式推送它:

if let dict = json as? [String: Any], {
    let token = dict["accessToken"] {
    let storyboard = UIStoryboard(name: "MyStoryboardName", bundle: nil)
    let abcViewController = storyboard.instantiateViewControllerWithIdentifier("YourControlleridentifier") as! YourViewController
YourViewController.token = token
navigationController?.pushViewController(YourViewController, animated: true)
}
}
Logo

ModelScope旨在打造下一代开源的模型即服务共享平台,为泛AI开发者提供灵活、易用、低成本的一站式模型服务产品,让模型应用更简单!

更多推荐