check user is login or not in IOS - ios5

I am making an IOS app in which I have some extra things for registered user so I made login form and it works perfectly but every time I run simulator I have to login so I just want to ask that how can I store the login user that when an registered user is login first time then login page opened but after login when user close their app and run again then its open next page from login.

use NSUserDefaults to store the flag variable to check the login status

For Saving Username and Password I will personally suggest to use Keychain as they are more safer than NSUserDefault in terms of security since Keychain stores data in encrypted form while NSUserDefault stores as plain text. If you still want to use NSUserDefault Here's the way
// create a standardUserDefaults variable
NSUserDefaults * standardUserDefaults = [NSUserDefaults standardUserDefaults];
// saving an NSString
[standardUserDefaults setObject:#"YES" forKey:#"Login"];
[standardUserDefaults synchronize];
//Check For Login
// create a standardUserDefaults variable
NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];
// getting an NSString object
NSString *Isallowed = [standardUserDefaults stringForKey:#"Login"];
if(Isallowed == #"YES"){
// Process for login
}
else
{
}

// create a standardUserDefaults variable
NSUserDefaults * standardUserDefaults = [NSUserDefaults standardUserDefaults];
// saving an NSString
[standardUserDefaults setObject:#"YES" forKey:#"Login"];
[standardUserDefaults synchronize];
//Check For Login
// create a standardUserDefaults variable
NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];
// getting an NSString object
NSString *Isallowed = [standardUserDefaults stringForKey:#"Login"];
if(Isallowed == #"YES"){
// Process for login
}
else
{
// Alert them for Not login
}

I'm gonna give you a comprehensive answer.
Don't use NSUserDefaults and don't store password it's a bad solution
NSUserDefaults data is not encrypted, it may cause security issue.
Let's create a structured user class instead
When the user logged in, you will need to make sure you have access to user data throughout the app so you can get the data on any screen when you need it.
To achieve this, we need to make a great structure to organize this properly. Remember that current user and another users are both "user" so we will use the same class.
Create a class and name it "EDUser" (you can choose other name if you want).
This class will contain a user information (either current user or other user).
More than that, this class will have capability to log the user in.
Here's a picture of what the class might look like:
class EDUser {
var firstName: String
var lastName: String?
var birthDate: NSDate?
init(firstName: String, lastName: String?, birthDate: NSDate?) {
self.firstName = firstName
self.lastName = lastName
self.birthDate = birthDate
}
}
// MARK: - Accessor
extension EDUser {
class var currentUser: EDUser? {
get {
return loadCurrentUserFromDisk()
}
set {
saveCurrentUserToDiskWithUser(newValue)
}
}
}
// MARK: - Log in and out
extension EDUser {
class func loginWithUsername(username: String,
andPassword password: String,
callback: (EDUser?, NSError) -> Void) {
// Access the web API
var parameters = [
"username": username,
"password": password
]
YourNetworkingLibrary.request(.POST,
"https://api.yourwebsite.com/login",
parameters: parameters).responseJSON {
response in
if response.statusCode == .Success {
let user = EDUser(firstName: response["firstName"],
lastName: response["lastName"],
birthDate: NSDate.dateFromString(response["birthDate"]))
currentUser = user
callback(currentUser, nil)
} else {
callback(nil, yourError)
}
}
}
class func logout() {
deleteCurrentUserFromDisk()
}
}
// MARK: - Data
extension EDUser {
class private func saveCurrentUserToDiskWithUser(user: EDUser) {
// In this process, you encode the user to file and store it
}
class private func loadCurrentUserFromDisk() -> EDUser? {
// In this process, you get the file and decode that to EDUser object
// This function will return nil if the file is not exist
}
class private func deleteCurrentUserFromDisk() {
// This will delete the current user file from disk
}
}
// MARK: - Helper
extension NSDate {
class func dateFromString(string: String) -> NSDate {
// convert string into NSDate
}
}
Use Case
Now with everything in place, we can use it like this
Non-blocking logging in process
EDUser.loginWithUsername(username: "edward#domain.com",
password: "1234") {
user, error in
if error == nil {
// Login succeeded
} else {
// Login failed
}
}
Logging out
EDUser.logout()
Check whether the user is logged in
if EDUser.currentUser != nil {
// The user is logged in
} else {
// No user logged in
// Show the login screen here
}
Get current user data on any screen
if let currentUser = EDUser.currentUser {
// do something with current user data
}
Store other user as object
let user = EDUser(firstName: "Edward",
lastName: "Anthony",
birthDate: NSDate())

Related

Firebase Twitter oAuth callback not working for Swift ios13

I have followed the instructions on https://firebase.google.com/docs/auth/ios/twitter-login to a T for Swift and I get the web popup to authorise the App I created on Twitter Dev, the callback is called and then the webview sits on an empty page of about:blank. Nothing can be done but click the Done button which then results in a Error Domain=FIRAuthErrorDomain Code=17058 "The interaction was cancelled by the user."
Callback address is correct. I've used the Twitter Consumer API Keys as the keys to enter in the Firebase console.
What am I missing?
For everyone who still has an issue with getting callback working, I managed to fix it. Sadly, you have to edit the method in the library (not the best way, but still. Bug was reported to firebase team). The method should look like the one below (you can find it in the file named FIROAuthProvider.m, line 125. I intentionally left commented lines, so you see the problem there... Hope it helps somebody :)
- (void)getCredentialWithUIDelegate:(nullable id<FIRAuthUIDelegate>)UIDelegate
completion:(nullable FIRAuthCredentialCallback)completion {
if (![FIRAuthWebUtils isCallbackSchemeRegisteredForCustomURLScheme:self->_callbackScheme]) {
[NSException raise:NSInternalInconsistencyException
format:#"Please register custom URL scheme '%#' in the app's Info.plist file.",
self->_callbackScheme];
}
// __weak __typeof__(self) weakSelf = self;
// __weak FIRAuth *weakAuth = _auth;
// __weak NSString *weakProviderID = _providerID;
dispatch_async(FIRAuthGlobalWorkQueue(), ^{
FIRAuthCredentialCallback callbackOnMainThread =
^(FIRAuthCredential *_Nullable credential, NSError *_Nullable error) {
if (completion) {
dispatch_async(dispatch_get_main_queue(), ^{
completion(credential, error);
});
}
};
NSString *eventID = [FIRAuthWebUtils randomStringWithLength:10];
NSString *sessionID = [FIRAuthWebUtils randomStringWithLength:10];
// __strong __typeof__(self) strongSelf = weakSelf;
[self
getHeadFulLiteURLWithEventID:eventID
sessionID:sessionID
completion:^(NSURL *_Nullable headfulLiteURL, NSError *_Nullable error) {
if (error) {
callbackOnMainThread(nil, error);
return;
}
FIRAuthURLCallbackMatcher callbackMatcher =
^BOOL(NSURL *_Nullable callbackURL) {
return [FIRAuthWebUtils
isExpectedCallbackURL:callbackURL
eventID:eventID
authType:kAuthTypeSignInWithRedirect
callbackScheme:self->_callbackScheme];
};
// __strong FIRAuth *strongAuth = weakAuth;
[_auth.authURLPresenter
presentURL:headfulLiteURL
UIDelegate:UIDelegate
callbackMatcher:callbackMatcher
completion:^(NSURL *_Nullable callbackURL,
NSError *_Nullable error) {
if (error) {
callbackOnMainThread(nil, error);
return;
}
NSString *OAuthResponseURLString =
[self OAuthResponseForURL:callbackURL
error:&error];
if (error) {
callbackOnMainThread(nil, error);
return;
}
__strong NSString *strongProviderID = _providerID;
FIROAuthCredential *credential = [[FIROAuthCredential alloc]
initWithProviderID:strongProviderID
sessionID:sessionID
OAuthResponseURLString:OAuthResponseURLString];
callbackOnMainThread(credential, nil);
}];
}];
});
}
For me there was no need in framework modifications.
As stated in a issue on GitHub: provider property should be
declared at a class or global level
So I just moved its initialisation out of a function.
Before:
class AuthViewController: UIViewController {
private func signIn() {
let provider = OAuthProvider(providerID: "twitter.com")
provider.getCredentialWith(nil) {
...
}
}
}
After:
class AuthViewController: UIViewController {
private let provider = OAuthProvider(providerID: "twitter.com")
private func signIn() {
provider.getCredentialWith(nil) {
...
}
}
}
Ok so I resolved this question but not entirely sure how now. I believe it was because the callback wasn't being issued and thus not picked up by the app. The callback wasn't issue due to the authentication and I believe because I hadn't created the terms of service and privacy policy. So make sure you have done that in the Twitter dev page.
In the twitter dev page, the callback link is: https://yourApp.firebaseapp.com/__/auth/handler
You'll find this in your firebase authentication settings when you enable twitter.
Ensure you have in info.plist LSApplicationQueriesSchemes an array of:
twitter
twitterauth
In your swift file:
var provider = OAuthProvider(providerID: "twitter.com")
Your button action:
#IBAction func onCustonTwitterButtonPressed(_ sender: Any) {
MyAppsCoreServicesScripts.logoutSocial() // My logout routine.
provider.getCredentialWith(nil) { credential, error in
if let error = error {
MyAppsCoreServicesScripts.showError(prefix: "Twitter Login",error: error, showMsg: true)
} else if credential != nil {
self.firebaseLogin(credential!)
}
}
}
Good luck! Hope this helps someone.
Got stucked in about:blank page for days, tried all the above but not working, solved by add following code in AppDelegate
func application(_ app: UIApplication, open url: URL, options: func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
let twitterhandeled = Auth.auth().canHandle(url)
return twitterhandeled
}

Checking Sign-in Status for Each ViewController

I am a beginner. I am developing an app with swift. I am using Firebase for signin. But I was wondering if I need to write codes to check user's sign-in status for each viewController for security. Or sign-in is needed only for the sign-in viewController like locking just a front door. My code may not be needed but below is the code that I wrote:
// Mark: User Sign-in Status Recheck
Auth.auth().addStateDidChangeListener { auth, user in
if user != nil {
if let user = user {
let userUid = user.uid
let userEmail = user.email
}
} else {
let InitialSignInFirstViewController = self.storyboard?.instantiateViewController(withIdentifier: "SignInFirstViewController") as! InitialSignInViewController
self.present(SignInFirstViewController, animated: false, completion: nil)
}
}
In my app I have a swift page that checks if the user is signed in when the app loads. If they are signed in they continue to the app, and you don't need to check until the app quits, and opens again. If they aren't signed in they go to another view controller to get signed in.
You don't need to manage the state or run the listener, there is more simpler way to do that, i.e.,
if Auth.auth().currentUser != nil {
// User is signed in.
// ...
} else {
// No user is signed in.
// ...
}
Update
You can create one class which just provide the user sign in status like below:
struct UserSignInStatus {
var isLoggedIn: Bool {
return (Auth.auth().currentUser != nil)
}
}
Usage: UserSignInStatus.isLoggedIn
You can put this code any where like in your AppDelegate class where you check the signin status and depending on that managing your rootViewController. Let me know if you need any more help.

How to get login username with AWS Mobile-hub SDK

I've been working for a while on the login part of my app. I'm trying to use ASW Mobile Hub for this matter. I found a way to get it work with the different providers I need: my own user pool, FB and Google.
The problem is that I've been searching here and all over the AWS documentation trying to find the way to get user data (Username and some othe user data like picture, email and so on). I can get it if I'm using the FBSDK directly (usingFBSDKGraphRequest) but I don't know how to do it if the user choose to login in my cognito-user-pool. Also I cannot see what provider the user used once succeeded.
I can find some other ways to get that, but using the old SDK o directly Cognito calls and initially is not what I need. Here's the code I'm using to present the login window:
override func viewDidLoad() {
super.viewDidLoad()
if !AWSSignInManager.sharedInstance().isLoggedIn {
presentAuthUIViewController()
}
}
func presentAuthUIViewController() {
let config = AWSAuthUIConfiguration()
config.enableUserPoolsUI = true
config.addSignInButtonView(class: AWSFacebookSignInButton.self)
config.addSignInButtonView(class: AWSGoogleSignInButton.self)
AWSAuthUIViewController.presentViewController(
with: self.navigationController!,
configuration: config, completionHandler: { (provider:
AWSSignInProvider, error: Error?) in
if error == nil {
// SignIn succeeded.
} else {
// end user faced error while loggin in, take any
required action here.
}
})
}
So, the question is, how can I get the relevant user info, once the signin is succeeded?
If the user used cognito login, you can use the below code to get the username.
let identityManager = AWSIdentityManager.default()
let identityUserName = identityManager.identityProfile?.userName
For retrieving the provider once user succeeds, keep it in the session as below
func onLogin(signInProvider: AWSSignInProvider, result: Any?,
authState: AWSIdentityManagerAuthState, error: Error?) {
let defaults = UserDefaults.standard
defaults.set(signInProvider.identityProviderName, forKey:
"identityProviderName")
}
Hope this answer helps.
Updated Code to get Username:
let pool = AWSCognitoIdentityUserPool.init(forKey: "CognitoUserPools")
let username = pool.currentUser()?.username
I've been working on a workaround till I sort this out in a more elegant way. I guess that I need to go deeper in Cognito's understanding. But the fact is even the sample provided by Amazon doesen't show the User's Name...
Sample Amazon app screen
So, in the meantime, I modified the source code of the Cognito library AWSUserPoolsUIOperations to send me the data directly to my app, on a message:
#implementation AWSUserPoolsUIOperations
-(void)loginWithUserName:(NSString *)userName
password:(NSString *)password
navigationController:(UINavigationController *)navController
completionHandler:(nonnull void (^)(id _Nullable, NSError *
_Nullable))completionHandler {
self.userName = userName;
NSDictionary* userInfo = #{#"username": self.userName};
[[NSNotificationCenter defaultCenter]
postNotificationName:#"UsernameNotification"
object:nil userInfo:userInfo];
And then just getting the message in the app and storing the value.
#objc private func TestNotification(_ notification: NSNotification){
if let dict = notification.userInfo as NSDictionary? {
if let username = dict["username"] as? String {
appEstats.username = username
defaults.set(username, forKey: sUserName)
}
}
}
As I said is not the solution but in the meantime it works.

sign out for Facebook and Google

I am trying to implement a sign out button that depending on the current user type (Facebook vs Google) it will sign out based on which type of current user is logged in. I am able to login with different accounts but want the sign out function to be conditional based on what type of account is logged in...thanks in advance!
// sign out functions
func handleSignOut() {
// facebook sign out
UserDefaults.standard.setIsLoggedIn(value: false)
FBSDKLoginManager().logOut()
print("did log out of facebook...")
// google signout
let firebaseAuth = FIRAuth.auth()
do {
try firebaseAuth?.signOut()
} catch let signOutError as NSError {
print ("Error signing out: %#", signOutError)
}
let loginController = LoginController()
present(loginController, animated: true, completion: nil)
}
func loginButtonDidLogOut(_ loginButton: FBSDKLoginButton!) {
do {
try FIRAuth.auth()!.signOut()
} catch let logoutError {
print(logoutError)
}
}
Try storing in the UserDefaults which account your user is signed in as (e.g. store a "account" key with a string value "google" or "facebook").
Then, in your sign-out method, handleSignOut() {...}, test for that value, i.e.
let at = (UserDefaults.getAccountType())
if at == "google" {
handleGoogle()
} else if at == "facebook" {
handleFacebook()
}
*Implement your own accessor for UserDefaults.getAccountType

How Save UILocalNotifications in CoreData

Answer is below, image is here:
I was searching how to do this for a couple of days and was only able to find people who stored UILocalNotificaations in NSUserDefaults. Saving these in NSUserDefaults seemed wrong to me because it is supposed to be used for small flags. I just now finally figured out how to store notifications in CoreData. This is Using Xcode 7.3.1 and Swift 2.2
First off you need to create a new entity in your CoreDataModel
and then add a single attribute to it. the attribute should be of type Binary Data I named my table/entity "ManagedFiredNotifications" and my attribute "notification". it should look like this:
Image linked in Question above.
Next you need to add an extension to UILocalNotification it should go like this:
extension UILocalNotification {
func save() -> Bool {
let appDelegate = UIApplication.sharedApplication().delegate as? AppDelegate
let firedNotificationEntity = NSEntityDescription.insertNewObjectForEntityForName("ManagedFiredNotifications", inManagedObjectContext: appDelegate!.managedObjectContext)
guard appDelegate != nil else {
return false
}
let data = NSKeyedArchiver.archivedDataWithRootObject(self)
firedNotificationEntity.setValue(data, forKey: "notification")
do {
try appDelegate!.managedObjectContext.save()
return true
} catch {
return false
}
}
}
Now for saving a notification all you need to do is call
UILocalNotification.save()
On the notification you would like to save. my notifications were named 'notification' so I would call notification.save()
To retrieve a notification you need a method like this
func getLocalFiredNotifications() -> [UILocalNotification]? {
let managedObjectContext = (UIApplication.sharedApplication().delegate as? AppDelegate)!.managedObjectContext
let firedNotificationFetchRequest = NSFetchRequest(entityName: "ManagedFiredNotifications")
firedNotificationFetchRequest.includesPendingChanges = false
do {
let fetchedFiredNotifications = try managedObjectContext.executeFetchRequest(firedNotificationFetchRequest)
guard fetchedFiredNotifications.count > 0 else {
return nil
}
var firedNotificationsToReturn = [UILocalNotification]()
for managedFiredNotification in fetchedFiredNotifications {
let notificationData = managedFiredNotification.valueForKey("notification") as! NSData
let notificationToAdd = NSKeyedUnarchiver.unarchiveObjectWithData(notificationData) as! UILocalNotification
firedNotificationsToReturn.append(notificationToAdd)
}
return firedNotificationsToReturn
} catch {
return nil
}
}
Note that this returns an array of UILocalNotifications.
When retrieving these if you plan on removing a few of them and then storing the list again you should remove them when you get them something like this works:
func loadFiredNotifications() {
let notifications = StudyHelper().getLocalFiredNotifications()
if notifications != nil {
firedNotifications = notifications!
} else {
// throw an error or log it
}
classThatRemoveMethodIsIn().removeFiredLocalNotifications()
}
I hope this helps someone who had the same problems that I did trying to implement this.