0

I am new to firebase , but I managed to develop an app using firebase -email&password authentication This app is for an organization's members so there is no sign up on the app , the organization gives me a list which I add to user list.My problem here is , I have only 45 registered users ,but there are almost 85 who are using the app.I understand I should be using an auth token , but I am not quite clear.Can anybody explain the easiest way I could prevent multiple logins simultaneously ? I have attached the login code ( I tried storing device names , but was a bad way )so can anybody please help me out on what has to be done?

public class EmailLogin extends AppCompatActivity implements
        View.OnClickListener {
    public String  Email;
    private static final String TAG = "EmailPassword";
public  static  int  device = 0;
    private TextView forgoPwd;
    private TextView mDetailTextView;
    private EditText mEmailField;
    private EditText mPasswordField;
    private ProgressDialog PD;
    private CheckBox saveLoginCheckBox;
    private SharedPreferences loginPreferences;
    private SharedPreferences.Editor loginPrefsEditor;
    private Boolean saveLogin;
    // [START declare_auth]
    private FirebaseAuth mAuth;
    // [END declare_auth]
    private DatabaseReference root;
    // [START declare_auth_listener]
    private FirebaseAuth.AuthStateListener mAuthListener;
    // [END declare_auth_listener]
    private String  temp_key;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setContentView(R.layout.emailpass);


        PD = new ProgressDialog(this);
        PD.setMessage("Loading...");
        PD.setCancelable(true);
        PD.setCanceledOnTouchOutside(false);
        // Views

        mEmailField = (EditText) findViewById(R.id.field_email);
        Email = mEmailField.toString();
        mPasswordField = (EditText) findViewById(R.id.field_password);
        Button btnCount = (Button) findViewById(R.id.email_sign_in_button);
       // Button regis = (Button) findViewById(R.id.regis);
        saveLoginCheckBox = (CheckBox)findViewById(R.id.checkBox);
        loginPreferences = getSharedPreferences("loginPrefs", MODE_PRIVATE);
        loginPrefsEditor = loginPreferences.edit();
        saveLogin = loginPreferences.getBoolean("saveLogin", false);
        if (saveLogin == true) {
            mEmailField.setText(loginPreferences.getString("username", ""));
            mPasswordField.setText(loginPreferences.getString("password", ""));
            saveLoginCheckBox.setChecked(true);
        }


        //regis.setOnClickListener(this);
        forgoPwd = (TextView)findViewById(R.id.forgo);
        forgoPwd.setOnClickListener(this);
        // Buttons
        btnCount.setOnClickListener(this);
        //  findViewById(R.id.email_create_account_button).setOnClickListener(this);
        //   findViewById(R.id.sign_out_button).setOnClickListener(this);

        // [START initialize_auth]
        mAuth = FirebaseAuth.getInstance();
        // [END initialize_auth]

        // [START auth_state_listener]
        mAuthListener = new FirebaseAuth.AuthStateListener() {
            @Override
            public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) {
                FirebaseUser user = firebaseAuth.getCurrentUser();
                if (user != null) {
                    // User is signed in
                   Log.d(TAG, "onAuthStateChanged:signed_in:" + user.getUid());
                } else {
                    // User is signed out
                    Log.d(TAG, "onAuthStateChanged:signed_out");
                }
                // [START_EXCLUDE]
                updateUI(user);
                // [END_EXCLUDE]
            }
        };
        // [END auth_state_listener]
    }


    public ProgressDialog mProgressDialog;

    public void showProgressDialog() {
        if (mProgressDialog == null) {
            mProgressDialog = new ProgressDialog(this);
            mProgressDialog.setMessage(getString(R.string.loading));
            mProgressDialog.setIndeterminate(true);
        }
    }
    public void hideProgressDialog() {
        if (mProgressDialog != null && mProgressDialog.isShowing()) {
            mProgressDialog.dismiss();
        }
    }
    // [START on_start_add_listener]
    @Override
    public void onStart() {
        super.onStart();
        mAuth.addAuthStateListener(mAuthListener);
    }
    // [END on_start_add_listener]

    // [START on_stop_remove_listener]
    @Override
    public void onStop() {
        super.onStop();
        if (mAuthListener != null) {
            mAuth.removeAuthStateListener(mAuthListener);
        }
    }
    // [END on_stop_remove_listener]

    private void createAccount(String email, String password) {
        Log.d(TAG, "createAccount:" + email);
        if (!validateForm()) {
            return;
        }

        showProgressDialog();

        // [START create_user_with_email]
        mAuth.createUserWithEmailAndPassword(email, password)
                .addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
                    @Override
                    public void onComplete(@NonNull Task<AuthResult> task) {
                        Log.d(TAG, "createUserWithEmail:onComplete:" + task.isSuccessful());

                        // If sign in fails, display a message to the user. If sign in succeeds
                        // the auth state listener will be notified and logic to handle the
                        // signed in user can be handled in the listener.
                        if (!task.isSuccessful()) {
                            Toast.makeText(EmailLogin.this, R.string.auth_failed,
                                    Toast.LENGTH_SHORT).show();
                        }

                        // [START_EXCLUDE]
                        hideProgressDialog();
                        // [END_EXCLUDE]
                    }
                });
        // [END create_user_with_email]
    }

    private void signIn(String email, String password) {
        Log.d(TAG, "signIn:" + email);
        if (saveLoginCheckBox.isChecked()) {
            loginPrefsEditor.putBoolean("saveLogin", true);
            loginPrefsEditor.putString("username", mEmailField.getText().toString());
            loginPrefsEditor.putString("password", password);
            loginPrefsEditor.commit();
        } else {
            loginPrefsEditor.clear();
            loginPrefsEditor.commit();
        }
        if (!validateForm()) {
            return;
        }
        PD.show();
        showProgressDialog();

        // [START sign_in_with_email]
        mAuth.signInWithEmailAndPassword(email, password)
                .addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
                    @Override
                    public void onComplete(@NonNull Task<AuthResult> task) {
                        Log.d(TAG, "signInWithEmail:onComplete:" + task.isSuccessful());
                        if (task.isSuccessful())
                        {
                            onAuthSuccess(task.getResult().getUser());
                        }
                        // If sign in fails, display a message to the user. If sign in succeeds
                        // the auth state listener will be notified and logic to handle the
                        // signed in user can be handled in the listener.
                        if (!task.isSuccessful()) {
                            Log.w(TAG, "signInWithEmail:failed", task.getException());
                            Toast.makeText(EmailLogin.this, R.string.auth_failed,
                                    Toast.LENGTH_SHORT).show();
                        }

                        // [START_EXCLUDE]
                        if (!task.isSuccessful()) {

                            //    mStatusTextView.setText(R.string.auth_failed);
                        }PD.dismiss();
                        hideProgressDialog();
                        // [END_EXCLUDE]
                    }
                });
        // [END sign_in_with_email]
    }
    private void onAuthSuccess(FirebaseUser user) {

        if (device == 0)
getDeviceName();
        device++;
        String username = usernameFromEmail(user.getEmail());
        Intent intent = new Intent(getApplicationContext(),Home_screen.class);
        intent.putExtra("user",username);
        startActivity(intent);
        finish();
    }
    public String getDeviceName() {
        String manufacturer = Build.MANUFACTURER;
        String model = Build.MODEL;
        root = FirebaseDatabase.getInstance().getReference().child("users");
        doDb(manufacturer);
    return manufacturer+model ;
    }

    private void doDb(String manu) {
        Map<String,Object> map = new HashMap<String, Object>();
        temp_key = root.push().getKey();
        root.updateChildren(map);
        DatabaseReference mess_root = root.child(temp_key);
        Map<String,Object> map2 = new HashMap<String, Object>();
        String email = FirebaseAuth.getInstance().getCurrentUser().getEmail();
        int index = email.indexOf('@');
        email = email.substring(0,index);
        map2.put("user",email);
        map2.put("msg",manu);
        mess_root.updateChildren(map2);


    }




    private String usernameFromEmail(String email) {
        if (email.contains("@")) {
            return email.split("@")[0];
        } else {
            return email;
        }
    }
    private void signOut() {
        mAuth.signOut();
        updateUI(null);
    }

    private boolean validateForm() {
        boolean valid = true;

        String email = mEmailField.getText().toString();
        if (TextUtils.isEmpty(email)) {
            mEmailField.setError("Required.");
            valid = false;
        } else {
            mEmailField.setError(null);
        }

        String password = mPasswordField.getText().toString();
        if (TextUtils.isEmpty(password)) {
            mPasswordField.setError("Required.");
            valid = false;
        } else {
            mPasswordField.setError(null);
        }

        return valid;
    }

    private void updateUI(FirebaseUser user) {
        hideProgressDialog();
        if (user != null) {
            //Timer timer = new Timer();
            //timer.schedule(new TimerTask(){
            //    public void run() {
                    Intent i = new Intent(EmailLogin.this, Home_screen.class);
                    i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                    startActivity(i);
                    finish();
                //    return;
              //  }
           // }, 600000);

        }
      /*
        if (user != null) {

            Intent intent = new Intent(getApplicationContext(),Home_screen.class);
            startActivity(intent);
            finish();
            mStatusTextView.setText(getString(R.string.emailpassword_status_fmt, user.getEmail()));
            mDetailTextView.setText(getString(R.string.firebase_status_fmt, user.getUid()));

            findViewById(R.id.email_password_buttons).setVisibility(View.GONE);
            findViewById(R.id.email_password_fields).setVisibility(View.GONE);

        } */



        else {
//            mStatusTextView.setText(R.string.signed_out);
            //          mDetailTextView.setText(null);

            //   findViewById(R.id.email_password_buttons).setVisibility(View.VISIBLE);
            //  findViewById(R.id.email_password_fields).setVisibility(View.VISIBLE);

        }
    }

    @Override
    public void onClick(View v) {
        int i = v.getId();

        if (i == R.id.email_sign_in_button) {
            signIn(mEmailField.getText().toString(), mPasswordField.getText().toString());
        }
        //if(i == R.id.regis)
        {

        }
        if(i == R.id.forgo) {

            FirebaseAuth auth = FirebaseAuth.getInstance();
            String mail =  mEmailField.getText().toString();
            if (TextUtils.isEmpty(mail)) {
                mEmailField.setError("Required.");

            } else {
                auth.sendPasswordResetEmail(mEmailField.getText().toString())
                        .addOnCompleteListener(new OnCompleteListener<Void>() {
                            @Override
                            public void onComplete(@NonNull Task<Void> task) {
                                if (task.isSuccessful()) {
                                    Toast.makeText(EmailLogin.this, "Email sent to your account",
                                            Toast.LENGTH_SHORT).show();
                                }
                            }
                        });
            }

        }
    }


}
  • Use device id and auth token both. At time of login save device id along with a token. and every time check if user is already logged in on any device, if yes then delete old token and generate new token. – Satish Kr Apr 12 '17 at 05:45
  • I propose to use a session manager. You can track each session, and do logoff for all older sessions of the same login. – Vitalii Pro Apr 12 '17 at 06:30
  • A session manager is likely - thanks.But I'm a comparatively new , if you could get me a reference , it would be of great help.Thanks – Sandhya Krishnan Apr 12 '17 at 07:49

2 Answers2

2

You can employ a session manager, which just keeps track of the last session and terminates all other sessions for that user.

  • Generate a UUID on the client every time the app launches (lets call it sessionId). If the user is signed in, or when the user signs in, write that sessionId to the user's document in the remote database (lets call this field lastSessionId).
  • Listen for changes to this document for the currently-signed-in user and make note when lastSessionId changes.
  • When another client launches the app with the same auth credentials, that client is also given a random sessionId and that sessionId is also written to the database, to the same document, overwriting lastSessionId. All of the clients signed in with these credentials (including this client) see the change in lastSessionId and for every client where the local sessionId (that was generated on the client) does not equal the new lastSessionId, that client is automatically signed out, thus only allowing one client to be signed in at a time for each credential.
trndjc
  • 11,654
  • 3
  • 38
  • 51
-1

I understand I should be using an auth token

That won't work. Whenever a user signs in on a device, they get a new auth token. So the same user being signed in on two devices, will have to different auth tokens.

But they will have the same UID. So I'd actually store the uid and something that identifies the active device in the database.

activeDeviceByUser
  <uid>: <device ID>

Then remove that when the user signs out or disconnects.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • So I store UID and Device id.If there is another user trying to login now, I should match the UID with device id and decide if user should be allowed to login ? Also ,in my app ,users are logged in all the time , difference is if they using it actively or are they in background ( it would still work ?) – Sandhya Krishnan Apr 12 '17 at 05:47
  • You'll have to detect that the app is being backgrounded and then remove the node for that user. To be honest: it sounds like more work than it's worth, but then again: it's your app and you seem to care about this and consider it abuse. You can also simply log the devices for a user and use that to create an inventory on who is doing this. Maybe there is a legitimate use-case. – Frank van Puffelen Apr 12 '17 at 05:59
  • yes I have a valid use case , expecting the app to reach some 1000plus in about 5-6months , so I want to ready. What I was wondering is , if I store and then search for this UID and device ID every login , would it take too long ? I appreciate the help , thank you so much for taking time and responding.Also why doesn't firebase have this in-built , I am sure no developer wants their users to login simultaneously unless a special case. – Sandhya Krishnan Apr 12 '17 at 07:52
  • You **know** a user's UID, so that wouldn't require a *search* operation. In my experience most developer don't care nearly as much about this type of abuse as they care about the absolute number of paying customers. – Frank van Puffelen Apr 12 '17 at 08:01
  • yes exactly.For me , this issue is resulting in a lower number of the absolute paying customers.Thanks again.I will see how I could go on with your suggestion :) – Sandhya Krishnan Apr 12 '17 at 09:25