使用SQLite通过电子邮件忘记密码

时间:2019-09-23 15:50:04

标签: android android-sqlite

有什么方法可以在Android Studio中使用sqlite通过电子邮件忘记密码吗?我只看到过秘密密钥类型恢复,但是在发送电子邮件时什么也没看到。使用Firebase看到它。只是想知道在sqlite中是否可能。

1 个答案:

答案 0 :(得分:0)

是的,以下是一个基本示例,该示例允许使用新的重置密码发送电子邮件(它不生成或发送电子邮件,而是通过写入日志来复制该电子邮件)。

首先,数据库助手(SQLiteOpenHelper的子类)还包括安全例程:-

DatabaseHelper.java

public class DatabaseHelper extends SQLiteOpenHelper {

    public class DatabaseConstants {

        public static final String DBNAME = "mydatabase";
        public static final int DBVERSION = 1;

        public class UserTableConstants {

            public static final String TABLENAME = "user";
            public static final String USERID = BaseColumns._ID;
            public static final String USEREMAIL = "email";
            public static final String USERSALT = "salt";
            public static final String USERHASH= "hash";

            public static final String CRTSQL = "CREATE TABLE IF NOT EXISTS " +
                    TABLENAME + "("
                    + USERID + " INTEGER PRIMARY KEY, "
                    + USEREMAIL + " TEXT NOT NULL UNIQUE, "
                    + USERSALT + " TEXT NOT NULL, "
                    + USERHASH + " TEXT NOT NULL "
                    + ")";
        }
    }

    SQLiteDatabase mDB;

    public DatabaseHelper(Context context) {
        super(context, DatabaseConstants.DBNAME, null, DatabaseConstants.DBVERSION);
        mDB = this.getWritableDatabase();
    }

    /**
     * Called when the database is created for the first time. This is where the
     * creation of tables and the initial population of the tables should happen.
     *
     * @param db The database.
     */
    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(DatabaseConstants.UserTableConstants.CRTSQL);
    }
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }

    public boolean addUser(String email, String password) {
        SaltandHash sah = new SaltandHash(password);
        ContentValues cv = new ContentValues();
        cv.put(DatabaseConstants.UserTableConstants.USEREMAIL,email);
        cv.put(DatabaseConstants.UserTableConstants.USERSALT,sah.getSalt());
        cv.put(DatabaseConstants.UserTableConstants.USERHASH,sah.getHash());
        return (mDB.insert(DatabaseConstants.UserTableConstants.TABLENAME,null,cv) > 0);
    }

    public boolean loginUser(String email, String password) {
        boolean rv = false;
        Cursor csr = mDB.query(
                DatabaseConstants.UserTableConstants.TABLENAME,
                null,
                DatabaseConstants.UserTableConstants.USEREMAIL+"=?",
                new String[]{email},
                null,null,null
        );
        if (csr.moveToFirst()) {
            rv = checkPassword(
                    password,
                    csr.getString(
                            csr.getColumnIndex(DatabaseConstants.UserTableConstants.USERSALT)
                    ),
                    csr.getString(
                            csr.getColumnIndex(DatabaseConstants.UserTableConstants.USERHASH)
                    )
            );
        }
        csr.close();
        return rv;

    }

    public boolean resetPassword(String email) {
        Cursor csr = mDB.query(
                DatabaseConstants.UserTableConstants.TABLENAME,
                null,
                DatabaseConstants.UserTableConstants.USEREMAIL + "=?",
                new String[]{email},
                null,null,null
        );
        int rowCount = csr.getCount();
        csr.close();
        if (rowCount != 1) return false;
        String newPassword = generateRandomPassword();
        SaltandHash sah = new SaltandHash(newPassword);
        ContentValues cv = new ContentValues();
        cv.put(DatabaseConstants.UserTableConstants.USERSALT,sah.getSalt());
        cv.put(DatabaseConstants.UserTableConstants.USERHASH,sah.getHash());
        int result = mDB.update(DatabaseConstants.UserTableConstants.TABLENAME,cv, DatabaseConstants.UserTableConstants.USEREMAIL +"=?",new String[]{email});
        if (result != 1) return false;
        Log.d("NEWPASSWORD","A new password has been sent to " + email + " the password is " + newPassword);
        // SEND THE EMAIL FROM HERE
        return true;
    }

    private boolean checkPassword(String password, String salt, String hash) {
        byte[] saltdecoded = android.util.Base64.decode(salt, android.util.Base64.DEFAULT);
        byte[] hashdecoded = android.util.Base64.decode(hash, android.util.Base64.DEFAULT);
        byte[] comprehash;

        KeySpec ks = new PBEKeySpec(password.toCharArray(),saltdecoded,65536,128);
        try {
            SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
            comprehash = skf.generateSecret(ks).getEncoded();
        } catch (Exception e) {
            return false;
        }
        return Arrays.equals(hashdecoded,comprehash);
    }


    /**
     * SaltandHash class for generating and storing a salt and hash from
     * the given password.
     */
    private class SaltandHash {
        private byte[] salt;
        private byte[] hash;
        private boolean worked = true;

        SaltandHash(String password) {
            this.salt = new SecureRandom().generateSeed(32);
            KeySpec ks = new PBEKeySpec(
                    password.toCharArray(),
                    salt,
                    65536,
                    128
            );
            try {
                SecretKeyFactory skf =
                        SecretKeyFactory.getInstance(
                                "PBKDF2WithHmacSHA1"
                        );
                hash = skf.generateSecret(ks).getEncoded();
            } catch (Exception e) {
                worked = false;
            }
        }

        private String getHash(){
            return android.util.Base64.encodeToString(this.hash, android.util.Base64.DEFAULT);
        }

        private String getSalt() {
            return android.util.Base64.encodeToString(this.salt, android.util.Base64.DEFAULT);
        }

        private boolean ifSaltandHashOK() {
            return worked;
        }
    }

    private String generateRandomPassword() {
        int password_length = 32;
        String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.@#?abcdefghijklmnopqrstuvwxyz";
        Random rnd = new Random();
        StringBuilder sb = new StringBuilder();
        for (int i=0; i < password_length; i++ ) {
            int pos = rnd.nextInt(chars.length());
            sb.append(chars.substring(pos,pos+1));
        }
        return sb.toString();
    }
}
  • 这将管理一个表,该表包含用户的电子邮件,盐和哈希(而不是密码本身)。

  • 它包括用于:-

    的方法
    • 根据用户的电子邮件和提供的密码添加用户。
    • 使用给定的电子邮件地址和密码登录。
    • 重置密码
    • 和中间基础方法

第二个是来自活动的代码,该代码添加了一个用户,使用有效密码登录,然后没有密码,然后多次重置密码(对于未知电子邮件也不会重置密码(黑客尝试))。

然后最后尝试使用失败的原始密码登录(因为密码已重置)。

MainActivity.java

public class MainActivity extends AppCompatActivity {

    DatabaseHelper mDBHlpr;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mDBHlpr = new DatabaseHelper(this);

        // Add the user
        String userEmail = "Fred@FredsEmail.com";
        mDBHlpr.addUser(userEmail,"mypassword");

        loginUser(userEmail,"mypassword");
        loginUser(userEmail,"notmypassword");

        // Reset the password according to the email
        resetPassword(userEmail);
        resetPassword("hacker@hacker.mail.com");
        resetPassword(userEmail);
        resetPassword(userEmail);
        resetPassword(userEmail);
        loginUser(userEmail,"mypassword");
    }

    private void resetPassword(String email) {
        String TAG = "RESETPWRSLT";
        if (mDBHlpr.resetPassword(email)) {
            Log.d(TAG,"Password was reset and an email sent to " + email);
        } else {
            Log.d(TAG,"WARNING an attempt to reset a password failed for the email " + email);
        }
    }

    private void loginUser(String email, String password) {
        String TAG = "LOGINRSLT";
        if (mDBHlpr.loginUser(email,password)) {
            Log.d(TAG,"Login in attamept successful for " + email);
        } else {
            Log.d(TAG,"FAILED LOGIN IN ATTEMPT for " + email);
        }
    }
}

结果

运行上述日志时,包含日志(请注意,重置密码是随机设置的):-

2019-09-24 14:04:23.761  D/LOGINRSLT: Login in attamept successful for Fred@FredsEmail.com
2019-09-24 14:04:24.413  D/LOGINRSLT: FAILED LOGIN IN ATTEMPT for Fred@FredsEmail.com
2019-09-24 14:04:25.036  D/NEWPASSWORD: A new password has been sent to Fred@FredsEmail.com the password is WooFd5FvPgswTGCTzVmDomrXEzKpTy39
2019-09-24 14:04:25.036  D/RESETPWRSLT: Password was reset and an email sent to Fred@FredsEmail.com
2019-09-24 14:04:25.036  D/RESETPWRSLT: WARNING an attempt to reset a password failed for the email hacker@hacker.mail.com
2019-09-24 14:04:25.659  D/NEWPASSWORD: A new password has been sent to Fred@FredsEmail.com the password is qcwDMFDTaoYc4hosuSw6BMRet4Wq2RG#
2019-09-24 14:04:25.659  D/RESETPWRSLT: Password was reset and an email sent to Fred@FredsEmail.com
2019-09-24 14:04:26.282  D/NEWPASSWORD: A new password has been sent to Fred@FredsEmail.com the password is KlTk6uRaliLzQ3IC1Yqql9XV2xioEi#v
2019-09-24 14:04:26.282  D/RESETPWRSLT: Password was reset and an email sent to Fred@FredsEmail.com
2019-09-24 14:04:26.908  D/NEWPASSWORD: A new password has been sent to Fred@FredsEmail.com the password is voHtOZz7nAw?enAIErYW7KsimA2k@JQ0
2019-09-24 14:04:26.909  D/RESETPWRSLT: Password was reset and an email sent to Fred@FredsEmail.com
2019-09-24 14:04:27.533  D/LOGINRSLT: FAILED LOGIN IN ATTEMPT for Fred@FredsEmail.com