Web Authn(3/3)
修改登录逻辑,实现WebAuthn验证
This commit is contained in:
parent
043e70ab7d
commit
07caef2555
@ -16,7 +16,6 @@ use Webauthn\AuthenticatorAssertionResponse;
|
|||||||
use Webauthn\AuthenticatorAssertionResponseValidator;
|
use Webauthn\AuthenticatorAssertionResponseValidator;
|
||||||
use Webauthn\AuthenticatorAttestationResponse;
|
use Webauthn\AuthenticatorAttestationResponse;
|
||||||
use Webauthn\AuthenticatorAttestationResponseValidator;
|
use Webauthn\AuthenticatorAttestationResponseValidator;
|
||||||
use Webauthn\CeremonyStep\CeremonyStepManager;
|
|
||||||
use Webauthn\CeremonyStep\CeremonyStepManagerFactory;
|
use Webauthn\CeremonyStep\CeremonyStepManagerFactory;
|
||||||
use Webauthn\Denormalizer\WebauthnSerializerFactory;
|
use Webauthn\Denormalizer\WebauthnSerializerFactory;
|
||||||
use Webauthn\Exception\AuthenticatorResponseVerificationException;
|
use Webauthn\Exception\AuthenticatorResponseVerificationException;
|
||||||
@ -63,12 +62,12 @@ class UserController extends Controller
|
|||||||
],
|
],
|
||||||
[
|
[
|
||||||
'allow' => true,
|
'allow' => true,
|
||||||
'actions' => ['login', 'register', 'verify-two-factor'],
|
'actions' => ['login', 'register', 'verify-two-factor', 'verify-assertion', 'request-assertion-options'],
|
||||||
'roles' => ['?', '@'], // everyone can access public share
|
'roles' => ['?', '@'], // everyone can access public share
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'allow' => true,
|
'allow' => true,
|
||||||
'actions' => ['logout', 'setup-two-factor', 'change-password', 'download-recovery-codes', 'remove-two-factor', 'set-theme', 'change-name', 'create-credential-options', 'create-credential', 'request-assertion-options', 'verify-assertion', 'credential-list', 'credential-delete'],
|
'actions' => ['logout', 'setup-two-factor', 'change-password', 'download-recovery-codes', 'remove-two-factor', 'set-theme', 'change-name', 'create-credential-options', 'create-credential', 'credential-list', 'credential-delete'],
|
||||||
'roles' => ['@'], // only logged-in user can do these ( admin included )
|
'roles' => ['@'], // only logged-in user can do these ( admin included )
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
@ -174,14 +173,16 @@ class UserController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Displays the login page.
|
* 显示登录页并接收登录请求
|
||||||
* visit via https://devs.chenx221.cyou:8081/index.php?r=user%2Flogin
|
* GET时显示登录页,如果带有username参数则直接到输入密码页
|
||||||
|
* POST时验证用户名密码,如果用户启用了二步验证则重定向到二步验证页面
|
||||||
*
|
*
|
||||||
|
* @param string|null $username
|
||||||
* @return string|Response
|
* @return string|Response
|
||||||
* @throws InvalidConfigException
|
* @throws InvalidConfigException
|
||||||
* @throws \yii\httpclient\Exception
|
* @throws \yii\httpclient\Exception
|
||||||
*/
|
*/
|
||||||
public function actionLogin(): Response|string
|
public function actionLogin(string $username = null): Response|string
|
||||||
{
|
{
|
||||||
if (!Yii::$app->user->isGuest) {
|
if (!Yii::$app->user->isGuest) {
|
||||||
Yii::$app->session->setFlash('error', '账户已登录,请不要重复登录');
|
Yii::$app->session->setFlash('error', '账户已登录,请不要重复登录');
|
||||||
@ -190,36 +191,69 @@ class UserController extends Controller
|
|||||||
|
|
||||||
$model = new User(['scenario' => 'login']);
|
$model = new User(['scenario' => 'login']);
|
||||||
|
|
||||||
if ($model->load(Yii::$app->request->post()) && $model->validate()) {
|
if (($model->load(Yii::$app->request->post()) && $model->validate()) | $username !== null) {
|
||||||
// 根据 verifyProvider 的值选择使用哪种验证码服务
|
if ($model->password === null) {
|
||||||
list($verifyProvider, $captchaResponse, $isCaptchaValid) = $this->checkCaptcha();
|
if ($username !== null) {
|
||||||
|
$model->username = $username;
|
||||||
if (($captchaResponse !== null && $isCaptchaValid) || ($verifyProvider === 'None')) {
|
}
|
||||||
// 验证用户名和密码
|
|
||||||
$user = User::findOne(['username' => $model->username]);
|
$user = User::findOne(['username' => $model->username]);
|
||||||
if ($user !== null && $user->validatePassword($model->password)) {
|
if ($user === null) {
|
||||||
// 如果用户启用了二步验证,将用户重定向到二步验证页面
|
Yii::$app->session->setFlash('error', '用户不存在');
|
||||||
if ($user->is_otp_enabled) {
|
return $this->render('login', [
|
||||||
Yii::$app->session->set('login_verification', ['id' => $user->id]);
|
'model' => $model,
|
||||||
return $this->redirect(['user/verify-two-factor']);
|
]);
|
||||||
} else {
|
} elseif ($user->status === 0) {
|
||||||
//login without 2FA
|
Yii::$app->session->setFlash('error', '用户已停用,请联系管理员获取支持');
|
||||||
$user->last_login = date('Y-m-d H:i:s');
|
return $this->render('login', [
|
||||||
$user->last_login_ip = Yii::$app->request->userIP;
|
'model' => $model,
|
||||||
if (!$user->save(false)) {
|
]);
|
||||||
Yii::$app->session->setFlash('error', '登陆成功,但出现了内部错误');
|
}
|
||||||
}
|
$publicKeyCredentialSourceRepository = new PublicKeyCredentialSourceRepository();
|
||||||
Yii::$app->user->login($user, $model->rememberMe ? 3600 * 24 * 30 : 0);
|
$fidoCredentials = $publicKeyCredentialSourceRepository->findAllForUserEntity($user);
|
||||||
return $this->goHome();
|
if (empty($fidoCredentials) | $username !== null) { //未设置FIDO
|
||||||
}
|
return $this->render('_login1', [
|
||||||
} else {
|
'model' => $model,
|
||||||
Yii::$app->session->setFlash('error', '用户名密码错误或账户已禁用');
|
]);
|
||||||
|
} else { //已设置FIDO
|
||||||
|
return $this->render('_login2', [
|
||||||
|
'model' => $model,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Yii::$app->session->setFlash('error', '请等待验证码加载并完成验证');
|
// 根据 verifyProvider 的值选择使用哪种验证码服务
|
||||||
|
list($verifyProvider, $captchaResponse, $isCaptchaValid) = $this->checkCaptcha();
|
||||||
|
|
||||||
|
if (($captchaResponse !== null && $isCaptchaValid) || ($verifyProvider === 'None')) {
|
||||||
|
// 验证用户名和密码
|
||||||
|
$user = User::findOne(['username' => $model->username]);
|
||||||
|
if ($user !== null && $user->validatePassword($model->password)) {
|
||||||
|
// 如果用户启用了二步验证,将用户重定向到二步验证页面
|
||||||
|
if ($user->is_otp_enabled) {
|
||||||
|
Yii::$app->session->set('login_verification', ['id' => $user->id]);
|
||||||
|
return $this->redirect(['user/verify-two-factor']);
|
||||||
|
} else {
|
||||||
|
//login without 2FA
|
||||||
|
$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->user->login($user, $model->rememberMe ? 3600 * 24 * 30 : 0);
|
||||||
|
return $this->goHome();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Yii::$app->session->setFlash('error', '用户名密码错误或账户已禁用');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Yii::$app->session->setFlash('error', '请等待验证码加载并完成验证');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
return $this->render('login', [
|
||||||
|
'model' => $model,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
return $this->render('login', [
|
return $this->render('_login1', [
|
||||||
'model' => $model,
|
'model' => $model,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@ -703,13 +737,24 @@ class UserController extends Controller
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 请求验证选项
|
* 请求验证选项
|
||||||
|
* @param string|null $username
|
||||||
* @return Response
|
* @return Response
|
||||||
* @throws RandomException
|
* @throws RandomException
|
||||||
*/
|
*/
|
||||||
public function actionRequestAssertionOptions(): Response
|
public function actionRequestAssertionOptions(string $username = null): Response
|
||||||
{
|
{
|
||||||
$user = Yii::$app->user->identity;
|
$user = null;
|
||||||
|
if ($username !== null) {
|
||||||
|
$user = User::findOne(['username' => $username]);
|
||||||
|
if ($user === null) {
|
||||||
|
return $this->asJson(['message' => 'User not found']);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$user = Yii::$app->user->identity;
|
||||||
|
}
|
||||||
|
if ($user === null) {
|
||||||
|
return $this->asJson(['message' => 'Guest? Sure?']);
|
||||||
|
}
|
||||||
$publicKeyCredentialSourceRepository = new PublicKeyCredentialSourceRepository();
|
$publicKeyCredentialSourceRepository = new PublicKeyCredentialSourceRepository();
|
||||||
$registeredAuthenticators = $publicKeyCredentialSourceRepository->findAllForUserEntity($user);
|
$registeredAuthenticators = $publicKeyCredentialSourceRepository->findAllForUserEntity($user);
|
||||||
|
|
||||||
@ -736,10 +781,12 @@ class UserController extends Controller
|
|||||||
/**
|
/**
|
||||||
* 验证断言
|
* 验证断言
|
||||||
* 用于已登录情况下验证fifo设置是否成功
|
* 用于已登录情况下验证fifo设置是否成功
|
||||||
|
* @param int $is_login
|
||||||
|
* @param int $remember
|
||||||
* @return Response
|
* @return Response
|
||||||
* @throws JsonException
|
* @throws JsonException
|
||||||
*/
|
*/
|
||||||
public function actionVerifyAssertion(): Response
|
public function actionVerifyAssertion(int $is_login = 0,int $remember = 0): Response
|
||||||
{
|
{
|
||||||
$data = Yii::$app->request->getRawBody();
|
$data = Yii::$app->request->getRawBody();
|
||||||
|
|
||||||
@ -787,9 +834,19 @@ class UserController extends Controller
|
|||||||
return $this->asJson(['message' => $e->getMessage(), 'verified' => false]);
|
return $this->asJson(['message' => $e->getMessage(), 'verified' => false]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if ($is_login === 1) {
|
||||||
|
$user = User::findOne(['id' => $publicKeyCredentialSourceRepository1->user_id]);
|
||||||
|
$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->user->login($user, $remember===1 ? 3600 * 24 * 30 : 0);
|
||||||
|
}
|
||||||
// Optional, but highly recommended, you can save the credential source as it may be modified
|
// Optional, but highly recommended, you can save the credential source as it may be modified
|
||||||
// during the verification process (counter may be higher).
|
// during the verification process (counter may be higher).
|
||||||
$publicKeyCredentialSourceRepository1->saveCredential($publicKeyCredentialSource, '',false);
|
$publicKeyCredentialSourceRepository1->saveCredential($publicKeyCredentialSource, '', false);
|
||||||
return $this->asJson(['verified' => true]);
|
return $this->asJson(['verified' => true]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,10 +69,10 @@ class User extends ActiveRecord implements IdentityInterface
|
|||||||
['input_vault_secret', 'string', 'min' => 6, 'max' => 24],
|
['input_vault_secret', 'string', 'min' => 6, 'max' => 24],
|
||||||
[['encryption_key', 'otp_secret', 'recovery_codes', 'vault_secret'], 'string', 'max' => 255],
|
[['encryption_key', 'otp_secret', 'recovery_codes', 'vault_secret'], 'string', 'max' => 255],
|
||||||
[['last_login_ip'], 'string', 'max' => 45],
|
[['last_login_ip'], 'string', 'max' => 45],
|
||||||
[['username', 'password'], 'required', 'on' => 'login'],
|
[['username'], 'required', 'on' => 'login'],
|
||||||
[['username', 'password', 'email', 'password2'], 'required', 'on' => 'register'],
|
[['username', 'password', 'email', 'password2'], 'required', 'on' => 'register'],
|
||||||
['username', 'string', 'min' => 3, 'max' => 12],
|
['username', 'string', 'min' => 3, 'max' => 12],
|
||||||
['password', 'string', 'min' => 6, 'max' => 24, 'on' => 'register'],
|
['password', 'string', 'min' => 6, 'max' => 24],
|
||||||
['password2', 'compare', 'compareAttribute' => 'password', 'on' => 'register'],
|
['password2', 'compare', 'compareAttribute' => 'password', 'on' => 'register'],
|
||||||
['email', 'email', 'on' => 'register'],
|
['email', 'email', 'on' => 'register'],
|
||||||
['username', 'unique', 'on' => 'register'],
|
['username', 'unique', 'on' => 'register'],
|
||||||
|
54
views/user/_login1.php
Normal file
54
views/user/_login1.php
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
<?php
|
||||||
|
// username+password verify
|
||||||
|
use yii\bootstrap5\Html;
|
||||||
|
use yii\bootstrap5\ActiveForm;
|
||||||
|
use yii\helpers\Url;
|
||||||
|
use yii\web\JqueryAsset;
|
||||||
|
use yii\web\View;
|
||||||
|
use yii\widgets\Pjax;
|
||||||
|
|
||||||
|
/** @var yii\web\View $this */
|
||||||
|
/** @var app\models\User $model */
|
||||||
|
/** @var ActiveForm $form */
|
||||||
|
$this->title = '用户登录';
|
||||||
|
$this->params['breadcrumbs'][] = $this->title;
|
||||||
|
$verifyProvider = Yii::$app->params['verifyProvider'];
|
||||||
|
if ($verifyProvider === 'reCAPTCHA') {
|
||||||
|
$this->registerJsFile('https://www.recaptcha.net/recaptcha/api.js?hl=zh-CN', ['async' => true, 'defer' => true]);
|
||||||
|
} elseif ($verifyProvider === 'hCaptcha') {
|
||||||
|
$this->registerJsFile('https://js.hcaptcha.com/1/api.js?hl=zh-CN', ['async' => true, 'defer' => true]);
|
||||||
|
} elseif ($verifyProvider === 'Turnstile') {
|
||||||
|
$this->registerJsFile('https://challenges.cloudflare.com/turnstile/v0/api.js', ['async' => true, 'defer' => true]);
|
||||||
|
} ?>
|
||||||
|
<div class="user-login">
|
||||||
|
<h1><?= Html::encode($this->title) ?></h1>
|
||||||
|
|
||||||
|
<p>我们已经找到了你的账户,请在下方输入你的密码以继续:</p>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-5">
|
||||||
|
<?php $form = ActiveForm::begin(['action' => [Url::to('user/login')]]); ?>
|
||||||
|
|
||||||
|
<?= $form->field($model, 'username')->label('用户名')->textInput(['autofocus' => true, 'readonly' => true]) ?>
|
||||||
|
<?= $form->field($model, 'password')->passwordInput()->label('密码') ?>
|
||||||
|
<?= $form->field($model, 'rememberMe')->checkbox()->label('记住本次登录') ?>
|
||||||
|
<div class="form-group">
|
||||||
|
<?php if ($verifyProvider === 'reCAPTCHA'): ?>
|
||||||
|
<div class="g-recaptcha" data-sitekey="<?= Yii::$app->params['reCAPTCHA']['siteKey'] ?>"></div>
|
||||||
|
<?php elseif ($verifyProvider === 'hCaptcha'): ?>
|
||||||
|
<div class="h-captcha" data-sitekey="<?= Yii::$app->params['hCaptcha']['siteKey'] ?>"></div>
|
||||||
|
<?php elseif ($verifyProvider === 'Turnstile'): ?>
|
||||||
|
<div class="cf-turnstile" data-sitekey="<?= Yii::$app->params['Turnstile']['siteKey'] ?>"
|
||||||
|
data-language="zh-cn"></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<?= Html::submitButton('登录', ['class' => 'btn btn-primary']) ?>
|
||||||
|
</div>
|
||||||
|
<?php ActiveForm::end(); ?>
|
||||||
|
<div class="form-group">
|
||||||
|
<?= Html::a('回到上个页面', [Url::to('user/login')]) ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div><!-- user-login -->
|
45
views/user/_login2.php
Normal file
45
views/user/_login2.php
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
// username+fido verify
|
||||||
|
use app\assets\SimpleWebAuthnBrowser;
|
||||||
|
use yii\bootstrap5\Html;
|
||||||
|
use yii\bootstrap5\ActiveForm;
|
||||||
|
use yii\helpers\Url;
|
||||||
|
use yii\web\JqueryAsset;
|
||||||
|
use yii\web\View;
|
||||||
|
|
||||||
|
/** @var yii\web\View $this */
|
||||||
|
/** @var app\models\User $model */
|
||||||
|
/** @var ActiveForm $form */
|
||||||
|
JqueryAsset::register($this);
|
||||||
|
SimpleWebAuthnBrowser::register($this);
|
||||||
|
$this->title = '用户登录';
|
||||||
|
$this->params['breadcrumbs'][] = $this->title;
|
||||||
|
?>
|
||||||
|
<div class="user-login">
|
||||||
|
<h1><?= Html::encode($this->title) ?></h1>
|
||||||
|
|
||||||
|
<p>我们已经找到了你的账户,请在下方验证Passkey以继续:</p>
|
||||||
|
<div class="alert alert-success" role="alert" hidden>
|
||||||
|
<span id="webauthn_success"></span>
|
||||||
|
</div>
|
||||||
|
<div class="alert alert-danger" role="alert" hidden>
|
||||||
|
<span id="webauthn_error"></span>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-5">
|
||||||
|
<?php $form = ActiveForm::begin(['action' => '#']); ?>
|
||||||
|
<?= $form->field($model, 'username')->label('用户名')->textInput(['autofocus' => true, 'readonly' => true, 'id' => 'username']) ?>
|
||||||
|
<?= $form->field($model, 'rememberMe')->checkbox(['id' => 'rememberMe'])->label('记住本次登录') ?>
|
||||||
|
<div class="form-group">
|
||||||
|
<?= Html::button('登录', ['class' => 'btn btn-primary', 'id' => 'webauthn_verify']) ?>
|
||||||
|
</div>
|
||||||
|
<?php ActiveForm::end(); ?>
|
||||||
|
<div class="form-group">
|
||||||
|
<?= Html::a('不想使用Passkey? 回到传统登录方式', Url::to(['user/login', 'username' => $model->username])) ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div><!-- user-login -->
|
||||||
|
<?php
|
||||||
|
$this->registerJsFile('@web/js/login-core.js', ['depends' => [JqueryAsset::class], 'position' => View::POS_END]);
|
||||||
|
?>
|
@ -2,52 +2,33 @@
|
|||||||
|
|
||||||
use yii\bootstrap5\Html;
|
use yii\bootstrap5\Html;
|
||||||
use yii\bootstrap5\ActiveForm;
|
use yii\bootstrap5\ActiveForm;
|
||||||
|
use yii\web\JqueryAsset;
|
||||||
|
use yii\web\View;
|
||||||
|
use yii\widgets\Pjax;
|
||||||
|
|
||||||
/** @var yii\web\View $this */
|
/** @var yii\web\View $this */
|
||||||
/** @var app\models\User $model */
|
/** @var app\models\User $model */
|
||||||
/** @var ActiveForm $form */
|
/** @var ActiveForm $form */
|
||||||
|
|
||||||
$this->title = '用户登录';
|
$this->title = '用户登录';
|
||||||
$this->params['breadcrumbs'][] = $this->title;
|
$this->params['breadcrumbs'][] = $this->title;
|
||||||
$verifyProvider = Yii::$app->params['verifyProvider'];
|
?>
|
||||||
if ($verifyProvider === 'reCAPTCHA') {
|
|
||||||
$this->registerJsFile('https://www.recaptcha.net/recaptcha/api.js?hl=zh-CN', ['async' => true, 'defer' => true]);
|
|
||||||
} elseif ($verifyProvider === 'hCaptcha') {
|
|
||||||
$this->registerJsFile('https://js.hcaptcha.com/1/api.js?hl=zh-CN', ['async' => true, 'defer' => true]);
|
|
||||||
} elseif ($verifyProvider === 'Turnstile') {
|
|
||||||
$this->registerJsFile('https://challenges.cloudflare.com/turnstile/v0/api.js', ['async' => true, 'defer' => true]);
|
|
||||||
} ?>
|
|
||||||
<div class="user-login">
|
<div class="user-login">
|
||||||
<h1><?= Html::encode($this->title) ?></h1>
|
<h1><?= Html::encode($this->title) ?></h1>
|
||||||
|
|
||||||
<p>请在下方输入你的用户凭证:</p>
|
<p>请在下方输入你的用户名:</p>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-5">
|
<div class="col-lg-5">
|
||||||
<?php $form = ActiveForm::begin(); ?>
|
<?php $form = ActiveForm::begin(); ?>
|
||||||
|
|
||||||
<?= $form->field($model, 'username')->label('用户名')->textInput(['autofocus' => true]) ?>
|
<?= $form->field($model, 'username')->label('用户名')->textInput(['autofocus' => true]) ?>
|
||||||
<?= $form->field($model, 'password')->passwordInput()->label('密码') ?>
|
|
||||||
<?= $form->field($model, 'rememberMe')->checkbox()->label('记住本次登录') ?>
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<?php if ($verifyProvider === 'reCAPTCHA'): ?>
|
<?= Html::submitButton('下一步', ['class' => 'btn btn-primary']) ?>
|
||||||
<div class="g-recaptcha" data-sitekey="<?= Yii::$app->params['reCAPTCHA']['siteKey'] ?>"></div>
|
|
||||||
<?php elseif ($verifyProvider === 'hCaptcha'): ?>
|
|
||||||
<div class="h-captcha" data-sitekey="<?= Yii::$app->params['hCaptcha']['siteKey'] ?>"></div>
|
|
||||||
<?php elseif ($verifyProvider === 'Turnstile'): ?>
|
|
||||||
<div class="cf-turnstile" data-sitekey="<?= Yii::$app->params['Turnstile']['siteKey'] ?>" data-language="zh-cn"></div>
|
|
||||||
<?php endif; ?>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<?= Html::submitButton('登录', ['class' => 'btn btn-primary']) ?>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<?= Html::a('还没有账户? 点击注册', ['user/register']) ?>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<?= Html::a('忘记密码?', ['user/forget']) ?>
|
|
||||||
</div>
|
</div>
|
||||||
<?php ActiveForm::end(); ?>
|
<?php ActiveForm::end(); ?>
|
||||||
|
<div class="form-group">
|
||||||
|
<?= Html::a('还没有账户? 去注册', ['user/register']) ?>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div><!-- user-login -->
|
</div><!-- user-login -->
|
47
web/js/login-core.js
Normal file
47
web/js/login-core.js
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
const elemSuccess = document.getElementById('webauthn_success');
|
||||||
|
const elemError = document.getElementById('webauthn_error');
|
||||||
|
const { startAuthentication } = SimpleWebAuthnBrowser;
|
||||||
|
const elemBegin_v = document.getElementById('webauthn_verify');
|
||||||
|
const username_input = document.getElementById('username');
|
||||||
|
const remember = document.getElementById('rememberMe');
|
||||||
|
|
||||||
|
elemBegin_v.addEventListener('click', async () => {
|
||||||
|
elemSuccess.innerHTML = '';
|
||||||
|
elemError.innerHTML = '';
|
||||||
|
elemSuccess.parentElement.hidden = true;
|
||||||
|
elemError.parentElement.hidden = true;
|
||||||
|
const username = encodeURIComponent(username_input.value);
|
||||||
|
const resp = await fetch(`index.php?r=user%2Frequest-assertion-options&username=${username}`);
|
||||||
|
let asseResp;
|
||||||
|
try {
|
||||||
|
asseResp = await startAuthentication(await resp.json());
|
||||||
|
} catch (error) {
|
||||||
|
elemError.innerText = error;
|
||||||
|
elemError.parentElement.hidden = false;
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
const isChecked = remember.checked? 1 : 0;
|
||||||
|
const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
|
||||||
|
const verificationResp = await fetch(`index.php?r=user%2Fverify-assertion&is_login=1&remember=${isChecked}`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-CSRF-Token': csrfToken
|
||||||
|
},
|
||||||
|
body: JSON.stringify(asseResp),
|
||||||
|
});
|
||||||
|
const verificationJSON = await verificationResp.json();
|
||||||
|
if (verificationJSON && verificationJSON.verified) {
|
||||||
|
elemSuccess.innerHTML = '登录成功!1s后跳转到首页';
|
||||||
|
elemSuccess.parentElement.hidden = false;
|
||||||
|
setTimeout(() => {
|
||||||
|
window.location.href = 'index.php';
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
elemError.innerHTML = `Oh no, something went wrong! Response: <pre>${JSON.stringify(
|
||||||
|
verificationJSON,
|
||||||
|
)}</pre>`;
|
||||||
|
elemError.parentElement.hidden = false;
|
||||||
|
}
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user