You've already forked lubo_comment_query
							
							webauthn登录逻辑调整
This commit is contained in:
		| @@ -2,6 +2,7 @@ | ||||
| 
 | ||||
| namespace App\Http\Controllers; | ||||
| 
 | ||||
| use App\Models\User; | ||||
| use App\WebAuthn\Repository\PublicKeyCredentialSourceRepositoryImpl; | ||||
| use App\WebAuthn\WebAuthnService; | ||||
| use Cose\Algorithm\Manager; | ||||
| @@ -32,11 +33,6 @@ use Webauthn\TokenBinding\IgnoreTokenBindingHandler; | ||||
| 
 | ||||
| class UserWebAuthnController extends BaseController | ||||
| { | ||||
|     public function webauthn_login(Request $request) | ||||
|     { | ||||
|         return view("user.webauthn.login"); | ||||
|     } | ||||
| 
 | ||||
|     public function register_options(Request $request): PublicKeyCredentialCreationOptions | ||||
|     { | ||||
|         $userEntity = new PublicKeyCredentialUserEntity( | ||||
| @@ -49,17 +45,44 @@ class UserWebAuthnController extends BaseController | ||||
|         return WebAuthnService::createRequestOptions($userEntity, $challenge); | ||||
|     } | ||||
| 
 | ||||
|     public function login_options(Request $request): PublicKeyCredentialRequestOptions | ||||
|     public function login_options(Request $request) | ||||
|     { | ||||
|         $challenge = random_bytes(32); | ||||
|         $request->session()->put("webauthn_login_challenge", $challenge); | ||||
|         $username = $request->post("username", ""); | ||||
|         if ($username) { | ||||
|             $query = User::query(); | ||||
|             if (str_contains($username, "@")) { | ||||
|                 $query->where("email", "=", $username); | ||||
|             } else { | ||||
|                 $query->where("name", "=", $username); | ||||
|             } | ||||
|             $user = $query->first(); | ||||
|             if ($user) { | ||||
|                 $userHandle = (string) $user->id; | ||||
|             } else { | ||||
|                 return new Response([ | ||||
|                     "success" => false, | ||||
|                     "code" => 401, | ||||
|                     "message" => "无此用户" | ||||
|                 ], 401); | ||||
|             } | ||||
|         } else { | ||||
|             $userHandle = "0"; | ||||
|         } | ||||
|         $request->session()->put("webauthn_login_user", $userHandle); | ||||
|         $publicKeyCredentialRequestOptions = new PublicKeyCredentialRequestOptions( | ||||
|             $challenge | ||||
|         ); | ||||
|         $publicKeyCredentialRequestOptions->setUserVerification( | ||||
|             PublicKeyCredentialRequestOptions::USER_VERIFICATION_REQUIREMENT_REQUIRED | ||||
|         ); | ||||
|         $publicKeyCredentialRequestOptions->allowCredentials([]); | ||||
|         $publicKeyCredentialSources = WebAuthnService::getPublicKeyCredentialSourceRepository()->findAllForUserEntity( | ||||
|             new PublicKeyCredentialUserEntity("", $userHandle, "") | ||||
|         ); | ||||
|         array_map(function ($source) use ($publicKeyCredentialRequestOptions) { | ||||
|             $publicKeyCredentialRequestOptions->allowCredential($source->getPublicKeyCredentialDescriptor()); | ||||
|         } ,$publicKeyCredentialSources); | ||||
|         return $publicKeyCredentialRequestOptions; | ||||
|     } | ||||
| 
 | ||||
| @@ -120,7 +143,24 @@ class UserWebAuthnController extends BaseController | ||||
|         $publicKeyCredentialRequestOptions = new PublicKeyCredentialRequestOptions( | ||||
|             $request->session()->remove("webauthn_login_challenge") | ||||
|         ); | ||||
|         $publicKeyCredentialSources = WebAuthnService::getPublicKeyCredentialSourceRepository()->findAllForUserEntity( | ||||
|             new PublicKeyCredentialUserEntity("", "0", "") | ||||
|         ); | ||||
|         $publicKeyCredential = WebAuthnService::getPublicKeyCredentialLoader()->loadArray($request->json()->all()); | ||||
|         $userHandle = null; | ||||
|         foreach ($publicKeyCredentialSources as $source) { | ||||
|             if ($source->getPublicKeyCredentialId() === $publicKeyCredential->getRawId()) { | ||||
|                 $userHandle = $source->getUserHandle(); | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|         if ($userHandle === null) { | ||||
|             return new Response([ | ||||
|                 "success" => false, | ||||
|                 "code" => 401, | ||||
|                 "message" => "无此密钥" | ||||
|             ], 401); | ||||
|         } | ||||
|         $authenticatorAssertionResponse = $publicKeyCredential->getResponse(); | ||||
|         if (!$authenticatorAssertionResponse instanceof AuthenticatorAssertionResponse) { | ||||
|             //e.g. process here with a redirection to the public key login/MFA page.
 | ||||
| @@ -136,7 +176,7 @@ class UserWebAuthnController extends BaseController | ||||
|                 $authenticatorAssertionResponse, | ||||
|                 $publicKeyCredentialRequestOptions, | ||||
|                 ServerRequest::fromGlobals(), | ||||
|                 $authenticatorAssertionResponse->getUserHandle(), | ||||
|                 $userHandle, | ||||
|                 ["localhost"] | ||||
|             ); | ||||
|         } catch (\Throwable $e) { | ||||
|   | ||||
| @@ -3,6 +3,7 @@ | ||||
| namespace App\WebAuthn\Repository; | ||||
| 
 | ||||
| use App\Models\WebauthnCredential; | ||||
| use Illuminate\Database\Eloquent\Builder; | ||||
| use Webauthn\PublicKeyCredentialSource; | ||||
| use Webauthn\PublicKeyCredentialSourceRepository; | ||||
| use Webauthn\PublicKeyCredentialUserEntity; | ||||
| @@ -52,18 +53,18 @@ class PublicKeyCredentialSourceRepositoryImpl implements PublicKeyCredentialSour | ||||
|         /** | ||||
|          * @var WebauthnCredential | ||||
|          */ | ||||
|         return WebauthnCredential::query()->where(function ($query) use ($publicKeyCredentialId) { | ||||
|         return WebauthnCredential::query()->where(function (Builder $query) use ($publicKeyCredentialId) { | ||||
|             $query->where("credential_id", "=", base64_encode($publicKeyCredentialId)); | ||||
|         })->first(); | ||||
|     } | ||||
| 
 | ||||
|     private function findAllModelByTypeFree(): array | ||||
|     { | ||||
|         return WebauthnCredential::query()->where("type_free", "=", "1")->get()->toArray(); | ||||
|         return WebauthnCredential::query()->where("type_free", "=", "1")->get()->all(); | ||||
|     } | ||||
| 
 | ||||
|     private function findAllModelByUserId(string $userId): array | ||||
|     { | ||||
|         return WebauthnCredential::query()->where("user_id", "=", $userId)->get()->toArray(); | ||||
|         return WebauthnCredential::query()->where("user_id", "=", $userId)->get()->all(); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -13,13 +13,16 @@ const webauthn_login = useLogin({ | ||||
| window.webauthn_register = webauthn_register; | ||||
| window.webauthn_login = webauthn_login; | ||||
| (function() { | ||||
|     const button = window.document.getElementById("do_webauthn_login"); | ||||
|     if (button) { | ||||
|         button.addEventListener("click", function (e) { | ||||
|             const loginForm = window.document.getElementById("webauthn_login_form"); | ||||
|     console.log(loginForm) | ||||
|     if (loginForm) { | ||||
|         loginForm.addEventListener("submit", function (e) { | ||||
|             if (!loginForm) return; | ||||
|             e.preventDefault(); | ||||
|             const formData = new FormData(loginForm) | ||||
|             webauthn_login(formData) | ||||
|             webauthn_login({ | ||||
|                 username: formData.get("username") | ||||
|             }) | ||||
|                 .then(() => { | ||||
|                     // 成功登录 | ||||
|                     window.location.href = "/" | ||||
|   | ||||
| @@ -4,10 +4,11 @@ | ||||
|     <title>登录</title> | ||||
|     <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||||
|     <link href="{{ mix('/css/app.css') }}" rel="stylesheet"/> | ||||
|     <script src="{{ mix('/js/manifest.js') }}" rel="script"></script> | ||||
| </head> | ||||
| <body> | ||||
| @include("common.header") | ||||
| <form class="w-full lg:w-1/2 border-2 mx-auto my-2" action="" method="post" enctype="multipart/form-data"> | ||||
| <form class="w-full lg:w-1/2 border-2 mx-auto my-2" id="webauthn_login_form" action="" method="post" enctype="multipart/form-data"> | ||||
|     <div class="block text-lg font-bold ml-4 mt-2">登录</div> | ||||
|     @csrf | ||||
|     <label class="block my-2"> | ||||
| @@ -25,11 +26,12 @@ | ||||
|     @include("common.form_error") | ||||
|     <div class="block my-2 text-center"> | ||||
|         <input class="px-6 py-2 inline-block rounded-full bg-cyan-600 text-white" type="submit" value="登录"> | ||||
|         <a class="px-6 py-2 inline-block rounded-full bg-cyan-600 text-white" href="{{ url(route("login.webauthn")) }}"> | ||||
|         <a class="px-6 py-2 inline-block rounded-full bg-cyan-600 text-white" id="do_webauthn_login" href="javascript: void 0"> | ||||
|             免输入登录<sup class="text-xs bg-yellow-600 text-white">Alpha</sup> | ||||
|         </a> | ||||
|     </div> | ||||
| </form> | ||||
| @include("common.footer") | ||||
| </body> | ||||
| <script src="{{ mix('/js/webauthn.js') }}" rel="script"></script> | ||||
| </html> | ||||
|   | ||||
| @@ -1,26 +0,0 @@ | ||||
| <html lang="zh"> | ||||
| <head> | ||||
|     <meta charset="UTF-8"> | ||||
|     <title>WebAuthn登录</title> | ||||
|     <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||||
|     <link href="{{ mix('/css/app.css') }}" rel="stylesheet"/> | ||||
|     <script src="{{ mix('/js/manifest.js') }}" rel="script"></script> | ||||
| </head> | ||||
| <body> | ||||
| @include("common.header") | ||||
| <form class="w-full lg:w-1/2 border-2 mx-auto my-2" id="webauthn_login_form" action="javascript:void 0" method="post" enctype="multipart/form-data"> | ||||
|     <div class="block text-lg font-bold ml-4 mt-2">登录</div> | ||||
|     @csrf | ||||
|     <label class="block my-2"> | ||||
|         用户名 | ||||
|         <input class="form-input border-0 border-b-2 w-full" type="text" name="username" value="{{ old("username") }}" placeholder="用户名或邮箱"> | ||||
|     </label> | ||||
|     @include("common.form_error") | ||||
|     <div class="block my-2 text-center"> | ||||
|         <input class="px-6 py-2 inline-block rounded-full bg-cyan-600 text-white" type="submit" value="免输入登录"> | ||||
|     </div> | ||||
| </form> | ||||
| @include("common.footer") | ||||
| </body> | ||||
| <script src="{{ mix('/js/webauthn.js') }}" rel="script"></script> | ||||
| </html> | ||||
| @@ -26,7 +26,6 @@ Route::post('/upload', ["\\App\\Http\\Controllers\\FileController","upload"]); | ||||
| // 用户部分
 | ||||
| Route::get('/login', ["\\App\\Http\\Controllers\\UserController", "login_page"])->name("login"); | ||||
| Route::post('/login', ["\\App\\Http\\Controllers\\UserController", "authenticate"])->name("login.submit"); | ||||
| Route::get('/login/webauthn/', ["\\App\\Http\\Controllers\\UserWebAuthnController", "webauthn_login"])->name("login.webauthn"); | ||||
| Route::post("/login/webauthn/options", ["\\App\\Http\\Controllers\\UserWebAuthnController", "login_options"])->name("login.webauthn.options"); | ||||
| Route::post("/login/webauthn/", ["\\App\\Http\\Controllers\\UserWebAuthnController", "login_validate"])->name("login.webauthn.submit"); | ||||
| Route::get('/register', ["\\App\\Http\\Controllers\\UserController", "register_page"])->name("register"); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user