totp前端设计(1/2)

后端快了,别急
This commit is contained in:
Chenx221 2024-03-06 20:14:47 +08:00
parent febc732e2d
commit 63bc49d63e
Signed by: chenx221
GPG Key ID: D7A9EC07024C3021
3 changed files with 79 additions and 17 deletions

View File

@ -354,21 +354,28 @@ class UserController extends Controller
return $this->redirect(['user/info', 'focus' => 'password']); return $this->redirect(['user/info', 'focus' => 'password']);
} }
/** public function actionSetupTwoFactor()
* @return string
*/
public function actionSetupTwoFactor(): string
{ {
$user = Yii::$app->user->identity; // ...其他代码...
$totp = TOTP::create();
$user->otp_secret = $totp->getSecret();
$user->is_otp_enabled = true;
$user->save(false);
$otpauth = $totp->getProvisioningUri($user->username); // 生成恢复代码
$qrCodeUrl = 'https://api.qrserver.com/v1/create-qr-code/?data=' . urlencode($otpauth); $recoveryCodes = $this->generateRecoveryCodes();
return $this->render('setup-two-factor', ['qrCodeUrl' => $qrCodeUrl]); // 保存恢复代码到数据库或其他安全的地方
// 显示恢复代码给用户
Yii::$app->session->setFlash('success', '二步验证已启用。您的恢复代码是:' . implode(', ', $recoveryCodes));
// ...其他代码...
}
private function generateRecoveryCodes($length = 10, $numCodes = 10)
{
$codes = [];
for ($i = 0; $i < $numCodes; $i++) {
$codes[] = Yii::$app->security->generateRandomString($length);
}
return $codes;
} }
} }

View File

@ -27,6 +27,7 @@ use yii\web\IdentityInterface;
* @property int|null $is_encryption_enabled 启用加密 * @property int|null $is_encryption_enabled 启用加密
* @property int|null $is_otp_enabled 启用otp * @property int|null $is_otp_enabled 启用otp
* @property int|null $storage_limit 存储容量限制,MB * @property int|null $storage_limit 存储容量限制,MB
* @property string|null $recovery_codes OTP恢复代码
* *
* @property CollectionTasks[] $collectionTasks * @property CollectionTasks[] $collectionTasks
* @property Share[] $shares * @property Share[] $shares
@ -39,6 +40,7 @@ class User extends ActiveRecord implements IdentityInterface
public $oldPassword; // 旧密码 修改密码用 public $oldPassword; // 旧密码 修改密码用
public $newPassword; // 新密码 修改密码用 public $newPassword; // 新密码 修改密码用
public $newPasswordRepeat; // 重复新密码 修改密码用 public $newPasswordRepeat; // 重复新密码 修改密码用
public $totp_input; // otp用户输入值
/** /**
* {@inheritdoc} * {@inheritdoc}
@ -57,7 +59,7 @@ class User extends ActiveRecord implements IdentityInterface
[['status', 'is_encryption_enabled', 'is_otp_enabled'], 'integer'], [['status', 'is_encryption_enabled', 'is_otp_enabled'], 'integer'],
[['created_at', 'last_login'], 'safe'], [['created_at', 'last_login'], 'safe'],
[['bio'], 'string'], [['bio'], 'string'],
[['encryption_key', 'otp_secret'], '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'],
[['username', 'password', 'email', 'password2'], 'required', 'on' => 'register'], [['username', 'password', 'email', 'password2'], 'required', 'on' => 'register'],
@ -112,6 +114,8 @@ class User extends ActiveRecord implements IdentityInterface
'is_encryption_enabled' => 'Is Encryption Enabled', 'is_encryption_enabled' => 'Is Encryption Enabled',
'is_otp_enabled' => 'Is Otp Enabled', 'is_otp_enabled' => 'Is Otp Enabled',
'storage_limit' => 'Storage Limit', 'storage_limit' => 'Storage Limit',
'recovery_codes' => 'Recovery Codes',
]; ];
} }

View File

@ -12,6 +12,7 @@
/* @var $totp_url string */ /* @var $totp_url string */
use app\assets\FontAwesomeAsset; use app\assets\FontAwesomeAsset;
use app\models\User;
use app\utils\FileSizeHelper; use app\utils\FileSizeHelper;
use app\utils\IPLocation; use app\utils\IPLocation;
use Endroid\QrCode\Color\Color; use Endroid\QrCode\Color\Color;
@ -56,6 +57,9 @@ if(!is_null($totp_secret)){
->setBackgroundColor(new Color(255, 255, 255)); ->setBackgroundColor(new Color(255, 255, 255));
$result = $writer->write($qrCode); $result = $writer->write($qrCode);
} }
// totp
$user = new User();
?> ?>
<div class="user-info"> <div class="user-info">
@ -235,11 +239,13 @@ if(!is_null($totp_secret)){
</h5> </h5>
<div> <div>
<div class="form-check form-switch"> <div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" id="totp-enabled"> <input class="form-check-input" type="checkbox" role="switch" id="totp-enabled"
<label class="form-check-label" for="totp-enabled">启用 TOTP</label> data-bs-toggle="modal"
data-bs-target="#totpSetupModal">
<label class="form-check-label" for="totp-enabled" data-bs-toggle="modal"
data-bs-target="#totpSetupModal">启用 TOTP</label>
</div> </div>
<!--暂时放在这里--> <!--暂时放在这里-->
<img src="<?= is_null($totp_secret)?'':$result->getDataUri() ?>" alt="qrcode"/>
</div> </div>
</li> </li>
<li class="list-group-item"> <li class="list-group-item">
@ -307,6 +313,51 @@ echo '</div>';
echo Html::endForm(); echo Html::endForm();
Modal::end();
Modal::begin([
'title' => '<h4>需要进一步操作以启用二步验证</h4>',
'id' => 'totpSetupModal',
'size' => 'model-xl',
]);
/*<img src="<?= is_null($totp_secret) ? '' : $result->getDataUri() ?>" alt="qrcode"/>*/
?>
<div class="row">
<div class="col-md-6 text-center center">
<img src="<?= is_null($totp_secret) ? '' : $result->getDataUri() ?>" alt="QR Code" class="img-fluid">
</div>
<div class="col-md-6">
<p>使用兼容TOTP的应用程序扫描左侧二维码以添加二步验证</p>
<p>推荐以下二步验证器::</p>
<ul>
<li>
<a href="https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2&hl=en_US">Google
Authenticator</a></li>
<li><a href="https://play.google.com/store/apps/details?id=com.azure.authenticator&hl=en_US">Microsoft Authenticator</a></li>
<li><a href="https://play.google.com/store/apps/details?id=com.authy.authy&hl=en">Authy</a></li>
<!-- Add more applications as needed -->
</ul>
<div class="input-group mb-3">
<label for="totp_secret">无法扫描?使用下面的密钥来添加</label>
<input type="text" class="form-control" value="<?= $totp_secret ?>" id="totp_secret" readonly>
<button class="btn btn-outline-secondary" type="button"
onclick="navigator.clipboard.writeText('<?= $totp_secret ?>')">Copy
</button>
</div>
<?php $form = ActiveForm::begin([
'action' => ['user/actionSetupTwoFactor'],
'method' => 'post'
]); ?>
<?= Html::activeHiddenInput($user, 'totp_secret', ['value' => $totp_secret]) ?>
<?= $form->field($user, 'totp_input')->textInput()->label('最后一步! 输入TOTP应用程序上显示的密码以启用二步验证') ?>
<?= Html::submitButton('启用二步验证', ['class' => 'btn btn-primary']) ?>
<?php ActiveForm::end(); ?>
</div>
</div>
<?php
Modal::end(); Modal::end();
$this->registerJsFile('@web/js/user-info.js', ['depends' => [JqueryAsset::class], 'position' => View::POS_END]); $this->registerJsFile('@web/js/user-info.js', ['depends' => [JqueryAsset::class], 'position' => View::POS_END]);
?> ?>