Обработка входа пользователя с помощью аутентификации на основе токена (несколько ViewControllers) в Swift - PullRequest
0 голосов
/ 28 февраля 2020

Я работаю над приложением и у меня возникают проблемы с входом в систему и переходом на основной ViewController.

Цель: Показать LoginViewController, если пользователь не вошел в систему, после входа перейдите к CannabisListViewController.

Прямо сейчас, когда я выбираю кнопку входа в симулятор, токен и дата истечения срока действия токена выводятся в заголовке. Я также подтвердил, что бэкэнд генерирует новый токен.

Ответ API

Server WSGIServer/0.2 CPython/3.7.2
Set-Cookie csrftoken=XelHDMTehmhJxLe5q6uqDYCymZV1iUaKNzRqtOcYYrmMvNkKTnuRbkjHEM2LR8Xo; expires=Fri, 26 Feb 2021 03:58:03 GMT; Max-Age=31449600; Path=/; SameSite=Lax, sessionid=5cu84ccaquq46ga8kazfjequ136y24g1; expires=Fri, 13 Mar 2020 03:58:03 GMT; HttpOnly; Max-Age=1209600; Path=/; SameSite=Lax
Date Fri, 28 Feb 2020 03:58:03 GMT
Content-Type application/json
Content-Length 50
Vary Accept, Cookie
X-Frame-Options SAMEORIGIN
Allow POST, OPTIONS

Бэкэнд: Django / Django Rest Framework & Django Rest Auth

Где я сейчас нахожусь: Я также использую UserDefaults для хранения того, что я считаю токеном, но я не уверен, что я ' я правильно его реализую или как сохранить токен, чтобы я мог проверить, существует ли он, и изменить ViewController на его основе.

SceneDelegate

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {


        // IF USER IS LOGGED IN
        if let _ = userToken?.key {

            // CREATE TAB BAR //
            let tabController = UITabBarController()

            // Instantiate the storyboards
            let cannabisStoryboard = UIStoryboard(name: "Cannabis", bundle: nil)
            let profileStoryboard = UIStoryboard(name: "Profile", bundle: nil)


             // Instantiate the view controllers to storyboards
             let cannabisVC = cannabisStoryboard.instantiateViewController(withIdentifier: "Cannabis") as! CannabisViewController
             let profileVC = profileStoryboard.instantiateViewController(withIdentifier: "Profile") as! ProfileViewController


             // Displays the items in below order in tab bar
             let vcData: [(UIViewController, UIImage, UIImage)] = [
                 (cannabisVC, UIImage(named: "Cannabis_icon")!, UIImage(named: "Cannabis_icon_selected")!),
                 (profileVC, UIImage(named: "Profile_icon")!, UIImage(named: "Profile_icon_selected")!),

             ]

             let vcs = vcData.map { (vc, defaultImage, selectedImage) -> UINavigationController in
                 let nav = UINavigationController(rootViewController: vc)
                 nav.tabBarItem.image = defaultImage
                 nav.tabBarItem.selectedImage = selectedImage

                 return nav
             }

             tabController.viewControllers = vcs
             tabController.tabBar.isTranslucent = false
             tabController.delegate = tabBarDelegate

             // Disables rendering for tab bar images
             if let items = tabController.tabBar.items {
                 for item in items {
                     if let image = item.image {
                         item.image = image.withRenderingMode(UIImage.RenderingMode.alwaysOriginal)
                     }

                     if let selectedImage = item.selectedImage {
                         item.selectedImage = selectedImage.withRenderingMode(UIImage.RenderingMode.alwaysOriginal)
                     }

                     // Hides title
                     item.imageInsets = UIEdgeInsets(top: 6, left: 0, bottom: -6, right: 0)
                 }
             }

             // Customize Navigation bar
             UINavigationBar.appearance().backgroundColor = UIColor(rgb: 0x00ffcc)

            //
             window?.rootViewController = tabController
             self.window?.makeKeyAndVisible()
             // CREATE TAB BAR //

    } else {
        let loginStoryboard = UIStoryboard(name: "Login", bundle: nil)
        let loginViewController = loginStoryboard.instantiateViewController(withIdentifier: "Login") as! LoginViewController
        window?.rootViewController = loginViewController
    }

        guard let _ = (scene as? UIWindowScene) else { return }

LoginViewController

import UIKit

class LoginViewController: UIViewController {

    // MARK: - Outlets
    @IBOutlet var usernameTextField: UITextField!
    @IBOutlet var passwordTextField: UITextField!
    @IBOutlet var loginButton: UIButton!


    // MARK: - Properties
    let rest = APIClient()


    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
    }


    // MARK: - Actions
    @IBAction func loginButtonDidTouch(_ sender: Any) {
        guard let username = usernameTextField.text else { return }
        guard let password = passwordTextField.text else { return }


        // MARK: URL
        guard let url = URL(string: APIClient.shared.loginURL) else { return }

//        rest.requestHttpHeaders.add(value: "application/x-www-form-urlencoded", forKey: "Content-Type")
        rest.requestHttpHeaders.add(value: "application/json", forKey: "Content-Type")
        rest.httpBodyParameters.add(value: "\(username)", forKey: "username")
        rest.httpBodyParameters.add(value: "\(password)", forKey: "password")

        rest.makeRequest(toURL: url, withHttpMethod: .post) { (results) in
            // MARK: Response
            print("\n\n### Response HTTP Headers ###\n")
            if let response = results.response {
                for (key, value) in response.headers.allValues() {
                print(key, value)
                }
            }
            print("\n\n### End Response HTTP Headers ###\n")

            // MARK: Data
            if let data = results.data {
                let decoder = JSONDecoder()
                decoder.keyDecodingStrategy = .convertFromSnakeCase

                guard let item = try? decoder.decode(CustomUser.self, from: data) else { return }
                print(item.key)

                let userAuthToken = item.key
                UserDefaults.standard.set(userAuthToken, forKey: "key")

                Helper.login()

            } else {
                print("Unable to serialize data")
            }

            DispatchQueue.main.async {
                let spinner = UIActivityIndicatorView(style: .medium)
                spinner.startAnimating()
                spinner.frame = CGRect(x: 0, y: 0, width: 5, height: 44)
            }

       }

        print(username)
        print(password)
    }

}

Вспомогательная функция (Это в основном делегат сцены, но я планирую использовать его для входа и выхода пользователя из профиля ViewViewController)

Функции входа / выхода (я также получаю предупреждение о слабой ссылке на TabBarDelegate, если кто-то захочет получить дополнительный вызов)

class Helper {
    class func login() {
        let tabController = UITabBarController()

           // Instantiate the storyboards
           let cannabisStoryboard = UIStoryboard(name: "Cannabis", bundle: nil)
           let profileStoryboard = UIStoryboard(name: "Profile", bundle: nil)


            // Instantiate the view controllers to storyboards
            let cannabisVC = cannabisStoryboard.instantiateViewController(withIdentifier: "Cannabis") as! CannabisViewController
            let profileVC = profileStoryboard.instantiateViewController(withIdentifier: "Profile") as! ProfileViewController


            // Displays the items in below order in tab bar
            let vcData: [(UIViewController, UIImage, UIImage)] = [
                (cannabisVC, UIImage(named: "Cannabis_icon")!, UIImage(named: "Cannabis_icon_selected")!),
                (profileVC, UIImage(named: "Profile_icon")!, UIImage(named: "Profile_icon_selected")!),

            ]

            let vcs = vcData.map { (vc, defaultImage, selectedImage) -> UINavigationController in
                let nav = UINavigationController(rootViewController: vc)
                nav.tabBarItem.image = defaultImage
                nav.tabBarItem.selectedImage = selectedImage

                return nav
            }

            tabController.viewControllers = vcs
            tabController.tabBar.isTranslucent = false
            tabController.delegate = TabBarDelegate() (Weak reference warning here)

            // Disables rendering for tab bar images
            if let items = tabController.tabBar.items {
                for item in items {
                    if let image = item.image {
                        item.image = image.withRenderingMode(UIImage.RenderingMode.alwaysOriginal)
                    }

                    if let selectedImage = item.selectedImage {
                        item.selectedImage = selectedImage.withRenderingMode(UIImage.RenderingMode.alwaysOriginal)
                    }

                    // Hides title
                    item.imageInsets = UIEdgeInsets(top: 6, left: 0, bottom: -6, right: 0)
                }
            }

            // Customize Navigation bar
            UINavigationBar.appearance().backgroundColor = UIColor(rgb: 0x00ffcc)

           //
        let appDelegate = UIApplication.shared.delegate as! AppDelegate
        guard let window = appDelegate.window else { return }
        window.rootViewController = tabController
    }

    class func logout() {
        let loginStoryboard = UIStoryboard(name: "Login", bundle: nil)
        let loginViewController = loginStoryboard.instantiateViewController(withIdentifier: "Login") as! LoginViewController
                let appDelegate = UIApplication.shared.delegate as! AppDelegate
        guard let window = appDelegate.window else { return }
        window.rootViewController = loginViewController
    }
}

Модель пользователя

struct CustomUser: Codable {
    static var current: CustomUser!
    var id: Int
    var username: String
    var password: String
    var email: String
    var photo: URL
    var token: String
    var key: String
}

Что происходит Как упоминалось ранее, когда я выбираю кнопку входа в LoginViewController, информация о токене распечатывается, но экран входа никогда не перемещается в основную часть приложения. Я предполагаю, что ошибка находится где-то в пределах хранения токена в UserDelegate и проверки, что он действительно существует, но я могу ошибаться.

Я пробовал искать в Google, но я в основном нахожу учебники по Auth0 (я планирую реализовать позже после лучшего понимания того, что я пытаюсь сделать сейчас) и FireBase.

Если есть лучший способ реализовать то, что я пытаюсь сделать, я также готов попробовать. Если у вас есть ссылка на учебник, который я могу просмотреть (и сохранить на потом), пожалуйста, поделитесь!

Заранее спасибо!

1 Ответ

0 голосов
/ 28 февраля 2020

guard let window = appDelegate.window else { return } Возвращается, так как appDelegate.window имеет значение nil.

Убедитесь, что ваш код устанавливает UITabbarController в правильное окно SceneDelegate.

...