实现恢复代码登录账户功能

*目前的安全策略是使用过的恢复代码将会失效
*其实想做的是在恢复后自动关掉二步验证:)
This commit is contained in:
Chenx221 2024-03-08 16:43:22 +08:00
parent dd23efda5b
commit 220b1abff6
Signed by: chenx221
GPG Key ID: D7A9EC07024C3021
3 changed files with 42 additions and 12 deletions

View File

@ -183,6 +183,7 @@ class UserController extends Controller
if ($model->load(Yii::$app->request->post())) { if ($model->load(Yii::$app->request->post())) {
// 验证二步验证代码 // 验证二步验证代码
if(!is_null($model->totp_input)){
$otp = TOTP::createFromSecret($user->otp_secret); $otp = TOTP::createFromSecret($user->otp_secret);
if ($otp->verify($model->totp_input)) { if ($otp->verify($model->totp_input)) {
$user->last_login = date('Y-m-d H:i:s'); $user->last_login = date('Y-m-d H:i:s');
@ -196,6 +197,27 @@ class UserController extends Controller
} else { } else {
Yii::$app->session->setFlash('error', '二步验证代码错误'); Yii::$app->session->setFlash('error', '二步验证代码错误');
} }
}elseif (!is_null($model->recoveryCode_input)) {
$recoveryCodes = explode(',', $user->recovery_codes);
if (in_array($model->recoveryCode_input, $recoveryCodes)) {
//remove the used recovery code
$recoveryCodes = array_diff($recoveryCodes, [$model->recoveryCode_input]);
$user->recovery_codes = implode(',', $recoveryCodes);
$user->last_login = date('Y-m-d H:i:s');
$user->last_login_ip = Yii::$app->request->userIP;
if (!$user->save(false)) {
Yii::$app->session->setFlash('error', '登陆成功,但出现了内部错误');
}
Yii::$app->session->setFlash('success', '登陆成功,但请注意已经使用的恢复代码已失效');
Yii::$app->user->login($user, $model->rememberMe ? 3600 * 24 * 30 : 0);
Yii::$app->session->remove('login_verification');
return $this->goHome();
} else {
Yii::$app->session->setFlash('error', '恢复代码错误');
}
}else{
Yii::$app->session->setFlash('error', '请输入二步验证代码或恢复代码');
}
} }
return $this->render('verifyTwoFactor', [ return $this->render('verifyTwoFactor', [

View File

@ -42,6 +42,7 @@ class User extends ActiveRecord implements IdentityInterface
public $newPassword; // 新密码 修改密码用 public $newPassword; // 新密码 修改密码用
public $newPasswordRepeat; // 重复新密码 修改密码用 public $newPasswordRepeat; // 重复新密码 修改密码用
public $totp_input; // otp用户输入值 public $totp_input; // otp用户输入值
public $recoveryCode_input; // 恢复代码用户输入
/** /**
* {@inheritdoc} * {@inheritdoc}
@ -59,7 +60,7 @@ class User extends ActiveRecord implements IdentityInterface
return [ return [
[['status', 'is_encryption_enabled', 'is_otp_enabled','dark_mode'], 'integer'], [['status', 'is_encryption_enabled', 'is_otp_enabled','dark_mode'], 'integer'],
[['created_at', 'last_login'], 'safe'], [['created_at', 'last_login'], 'safe'],
[['bio', 'totp_input'], 'string'], [['bio', 'totp_input','recoveryCode_input'], 'string'],
[['encryption_key', 'otp_secret', 'recovery_codes'], 'string', 'max' => 255], [['encryption_key', 'otp_secret', 'recovery_codes'], 'string', 'max' => 255],
[['last_login_ip'], 'string', 'max' => 45], [['last_login_ip'], 'string', 'max' => 45],
[['username', 'password'], 'required', 'on' => 'login'], [['username', 'password'], 'required', 'on' => 'login'],

View File

@ -23,6 +23,13 @@ $this->params['breadcrumbs'][] = $this->title;
<?= Html::submitButton('提交', ['class' => 'btn btn-primary']) ?> <?= Html::submitButton('提交', ['class' => 'btn btn-primary']) ?>
</div> </div>
<?php ActiveForm::end(); ?> <?php ActiveForm::end(); ?>
<hr>
<?php $form = ActiveForm::begin(); ?>
<?= $form->field($model, 'recoveryCode_input')->textInput()->label('丢失所有验证设备? 使用恢复代码') ?>
<div class="form-group">
<?= Html::submitButton('恢复账户', ['class' => 'btn btn-primary']) ?>
</div>
<?php ActiveForm::end(); ?>
</div> </div>
</div> </div>
</div><!-- user-login-2fa --> </div><!-- user-login-2fa -->