0

I try to keep the User logged in without using firebase. I look up different posts and couldn't find the right way to do it other than if I use the firebase.

   @IBAction func LoginTapped(_ sender: Any) {
        let authService = AuthenticationService()
        emailTextfield.resignFirstResponder()
        passwordTextfield.resignFirstResponder()
        
        authService.loginUser(email: email, password: password) { (isManager) in
        
            if let isManager = isManager {
                let storyboard = UIStoryboard(name: "Main", bundle: nil)
                DispatchQueue.main.async {
                    var viewController:UIViewController
                    if isManager{
                        viewController = storyboard.instantiateViewController(identifier: "managerEntryViewController")
                    }else{
                        viewController = storyboard.instantiateViewController(identifier: "clientEntryViewController")
                    }
                    viewController.modalPresentationStyle = .fullScreen
                    self.present(viewController, animated: true)
                }
            } else {
                DispatchQueue.main.async {
                    self.alertError()
                }
            }
        }
    }

In the AuthenticationService() there is already function created where the token is created for users who already signed in. I want to create logic where I if token valid or not.

fileprivate func saveToken(token: String) {
        UserDefaults.standard.set(token, forKey: NetworkConstants.tokenKey)
    }
    

This current Login function uses "authService" as a way to communicate with backend to pass email and password. Is it possible I can keep the user logged after the user went to the main screen in Xcode without using firebase? or it needs to be something done at the backend. Let me know if you need any additional explanations! I am happy to clarify!

  • https://firebase.google.com/docs/auth/ios/manage-users - refer to this. Fire base Auth provides a way to get the current user as login to fire base creates a session. Don’t use user defaults for this purpose as it is NOT safe – ram Jul 21 '20 at 01:45
  • @firestore-ram is there any way not to use firebase? – AnotherCoder Jul 21 '20 at 01:57
  • Since logins are session based - it may expire. So it will require you to keeping listening Auth state changes. Rest of the app need not be exposed to fire base - but you can add a method to AuthenticationService that will check the fire base method & return an Boolean – ram Jul 21 '20 at 02:01

2 Answers2

1

You can use UserDefaults to store a value that corresponds to telling you that the user is logged in. Here's how you store a value in UserDefaults.

Setting:

UserDefaults.standard.set(true, forKey: "isLoggedIn")

Retrieving:

let isLoggedIn = UserDefaults.standard.bool(forKey: "isLoggedIn")
Frankenstein
  • 15,732
  • 4
  • 22
  • 47
  • Thank you for the response, I have an additional question let say I have already created function ``` fileprivate func saveToken(token: String) { UserDefaults.standard.set(token, forKey: NetworkConstants.tokenKey) } ``` from class AuthenticationService then how do I make logic where I check if the token is valid (if check it's nill or not) and perform segue depend on that? – AnotherCoder Jul 21 '20 at 01:40
  • Comments aren't the right place to ask a follow-up question. Why don't post this as another question on SO? Will take a look and try figure out a solution if possible. – Frankenstein Jul 21 '20 at 04:27
1

1. Create Helper class:

    class UserHelper: NSObject {
    
        private static let userDefault = UserDefaults.standard
    
        public static var USER_TOKEN: TokenModel? {
           get {
                if let data = userDefault.value(forKey: "USER_TOKEN")as Data {
                    let _token = try? PropertyListDecoder().decode(TokenModel.self, from: data)
                    return _token
                }
                return nil
           }
           set {
                userDefault.set(try? PropertyListEncoder().encode(newValue), forKey: "USER_TOKEN")
           }
        
        }
    
        public static var USER: UserModel? {
            get {
                if let data = userDefault.object(forKey: "USER") as? Data {
                    let _user = try? PropertyListDecoder().decode(UserModel.self, from: data)

                   return _user
                }
                return nil
            }

            set {
                guard let value = newValue else {
                    return
                }
                if let data = try? PropertyListEncoder().encode(value) {
                    userDefault.set(data, forKey: "USER")
                }
           
            }
        }
    
        public static func removeAll() {
            userDefault.removePersistentDomain(forName: Bundle.main.bundleIdentifier!)
            userDefault.synchronize()
        }
    }

2. Usage:

  • Save object

    let data: UserModel = YOUR_DATA
    UserHelper.USER = data
    
  • Retrieve object

    if let user = UserHelper.USER {
        print("name of user = ", user.name)
    }
    
  • Remove object

    UserHelper.removeAll()
    

3. Model:

    struct UserModel: Codable {
        let id: Int
        let name: String
        let email: String

        private enum CodingKeys: String, CodingKey {
            case id, name, email
        }

        init(from decoder: Decoder) throws {
            let container = decoder.container(keyedBy: CodingKeys.self)
            id = try container.decode(Int.self, forKey: .id)
            name = try container.decode(String.self, forKey: .name)
            email = try container.decode(String.self, forKey: .email)
        }
    }


    struct TokenModel: Codable {
        let access_token: String
        let token_type: String

        enum CodingKeys: String, CodingKey {
            case access_token
            case token_type
        }

        init(from decoder: Decoder) throws {
            let container = try decoder.container(keyedBy: CodingKeys.self)
            access_token = try container.decode(String.self, forKey: .access_token)
            token_type = try container.decode(String.self, forKey: .token_type)
        }
   }

  
Bunthoeun
  • 143
  • 1
  • 1
  • 11
  • Even though the code is functional - user defaults is not right place to store login tokens. There has been lot of Stackoverflow discussions on this - https://stackoverflow.com/questions/16795506/storing-authentication-tokens-on-ios-nsuserdefaults-vs-keychain – ram Jul 23 '20 at 13:24