有什么方法可以在Android Studio中使用sqlite通过电子邮件忘记密码吗?我只看到过秘密密钥类型恢复,但是在发送电子邮件时什么也没看到。使用Firebase看到它。只是想知道在sqlite中是否可能。
答案 0 :(得分:0)
是的,以下是一个基本示例,该示例允许使用新的重置密码发送电子邮件(它不生成或发送电子邮件,而是通过写入日志来复制该电子邮件)。
首先,数据库助手(SQLiteOpenHelper的子类)还包括安全例程:-
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();
}
}
这将管理一个表,该表包含用户的电子邮件,盐和哈希(而不是密码本身)。
它包括用于:-
的方法第二个是来自活动的代码,该代码添加了一个用户,使用有效密码登录,然后没有密码,然后多次重置密码(对于未知电子邮件也不会重置密码(黑客尝试))。
然后最后尝试使用失败的原始密码登录(因为密码已重置)。
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