user("web")->name, $request->user("web")->id, $request->user("web")->name, ); $challenge = random_bytes(16); $request->session()->put("webauthn_register_challenge", $challenge); return WebAuthnService::createRequestOptions($userEntity, $challenge); } 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 ); $publicKeyCredentialSources = WebAuthnService::getPublicKeyCredentialSourceRepository()->findAllForUserEntity( new PublicKeyCredentialUserEntity("", $userHandle, "") ); array_map(function ($source) use ($publicKeyCredentialRequestOptions) { $publicKeyCredentialRequestOptions->allowCredential($source->getPublicKeyCredentialDescriptor()); } ,$publicKeyCredentialSources); return $publicKeyCredentialRequestOptions; } public function register_validate(Request $request) { if (!$request->session()->has("webauthn_register_challenge")) { return new Response([ "success" => false, "code" => 403, "message" => "重放攻击可能?无对应验证请求" ], 403); } $publicKeyCredential = WebAuthnService::getPublicKeyCredentialLoader()->loadArray($request->json()->all()); $authenticatorAttestationResponse = $publicKeyCredential->getResponse(); if (!$authenticatorAttestationResponse instanceof AuthenticatorAttestationResponse) { //e.g. process here with a redirection to the public key creation page. return new Response([ "success" => false, "code" => 400, "message" => "接口调用错误?无法验证请求" ], 400); } $userEntity = new PublicKeyCredentialUserEntity( $request->user("web")->name, $request->user("web")->id, $request->user("web")->name, ); $challenge = $request->session()->remove("webauthn_register_challenge"); $publicKeyCredentialCreationOptions = WebAuthnService::createRequestOptions($userEntity, $challenge); try { $publicKeyCredentialSource = WebAuthnService::getAuthenticatorAttestationResponseValidator()->check( $authenticatorAttestationResponse, $publicKeyCredentialCreationOptions, ServerRequest::fromGlobals(), ["localhost"] ); } catch (\Throwable $e) { return new Response([ "success" => false, "code" => 500, "message" => "服务器异常", "exception" => $e->getMessage() ], 500); } WebAuthnService::getPublicKeyCredentialSourceRepository()->saveCredentialSource($publicKeyCredentialSource); return $publicKeyCredentialSource; } public function login_validate(Request $request) { if (!$request->session()->has("webauthn_login_challenge")) { return new Response([ "success" => false, "code" => 403, "message" => "重放攻击可能?无对应验证请求" ], 403); } $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. return new Response([ "success" => false, "code" => 400, "message" => "接口调用错误?无法验证请求" ], 400); } try { $publicKeyCredentialSource = WebAuthnService::getAuthenticatorAssertionResponseValidator()->check( $publicKeyCredential->getRawId(), $authenticatorAssertionResponse, $publicKeyCredentialRequestOptions, ServerRequest::fromGlobals(), $userHandle, ["localhost"] ); } catch (\Throwable $e) { return new Response([ "success" => false, "code" => 500, "message" => "服务器异常", "exception" => $e->getMessage() ], 500); } Auth::loginUsingId($publicKeyCredentialSource->getUserHandle()); return [ "success" => true, "code" => 0, "message" => "登录成功", "userId" => $publicKeyCredentialSource->getUserHandle() ]; } }