2fa 验证和记忆设备, 与 Laravel 黄昏
原标题:2fa Authentication and remember device, with Laravel dusk
This bounty has ended. Answers to this question are eligible for a +100 reputation bounty. Bounty grace period ends in 20 hours. Fatih Toprak is looking for an answer from a reputable source.
I want to log in to a remote address with DUSK and verify with 2FA at the same time.
$this->browse(function (Browser $browser) {
$browser->visit( https://www.domain.tld );
$browser->pause(300);
$browser->typeSlowly( input[type="text"] , user@domain.tld );
$browser->pause(300);
$browser->typeSlowly( input[type="password"] , hereispassword );
$browser->pause(300);
$browser->click( button.button );
$browser->pause(300);
$browser->waitFor( input[type="number"] ,2000);
$browser->typeSlowly( input[type="number"] , 268313 );
$browser->pause(1000);
$browser->script( document.querySelector( [type="checkbox"] ).checked = true; );
$browser->pause(1000);
$browser->click( button.button );
$browser->pause(1000);
$browser->visit( https://backoffice.domain.tld );
$browser->pause(2000);
#$this->saveCookies($browser);
});
I log in successfully, but after 2FA verification, I want it to remember that browser when I run the test again and not ask for 2FA again.
I wanted to write cookies to the cookie.txt file for this, but;
invalid cookie domain
i got, cookie error.
private function saveCookies(Browser $browser) {
$cookies = $browser->driver->manage()->getCookies();
file_put_contents($this->cookie_file, serialize($cookies));
}
private function loadCookies(Browser $browser) {
if (file_exists($this->cookie_file)) {
//Get cookies from storage
$cookies = unserialize(file_get_contents($this->cookie_file));
//Add each cookie to this session
foreach ($cookies as $key => $cookie) {
$browser->driver->manage()->addCookie($cookie);
}
}
}
This is the part where I store the cookies and try to reload them? Where could I be making a mistake?
Thanks.
问题回答
To avoid 2FA verification repeatedly in Laravel Dusk you need to make sure that the domain for the cookies must matches with the domain of the website which you are trying to visit. Moreover, the cookies are not expired and they should have correct path.
Following is the more refined code as it:
Load cookies before visiting the page.
Added isLoggedIn method.
Only cookies with the correct domain are stored.
Set correct domain and path for the cookies.
public function testLoginWith2FA() {
$this->browse(function (Browser $browser) {
// Load cookies before visiting the login page
$this->loadCookies($browser);
$browser->visit( https://www.domain.tld )
->pause(300);
// Check if the user is already logged in
if (!$this->isLoggedIn($browser)) {
$browser->typeSlowly( input[type="text"] , user@domain.tld )
->pause(300)
->typeSlowly( input[type="password"] , hereispassword )
->pause(300)
->click( button.button )
->pause(300)
->waitFor( input[type="number"] , 2000)
->typeSlowly( input[type="number"] , 268313 )
->pause(1000)
->script( document.querySelector( [type="checkbox"] ).checked = true; )
->pause(1000)
->click( button.button )
->pause(1000);
// Save cookies after successful login
$this->saveCookies($browser);
}
// Visit the back office page after login
$browser->visit( https://backoffice.domain.tld )
->pause(2000);
});
}
private function saveCookies(Browser $browser) {
$cookies = $browser->driver->manage()->getCookies();
// Filter cookies to ensure correct domain
$filteredCookies = array_filter($cookies, function ($cookie) {
return isset($cookie[ domain ]) && $cookie[ domain ] == www.domain.tld ;
});
file_put_contents($this->cookie_file, serialize($filteredCookies));
}
/// Modified Version
private function loadCookies(Browser $browser) {
if (file_exists($this->cookie_file)) {
$cookies = unserialize(file_get_contents($this->cookie_file));
foreach ($cookies as $cookie) {
// Ensure that the domain is correctly set for each cookie
if (!isset($cookie[ domain ]) || strpos($cookie[ domain ], domain.tld ) === false) {
$cookie[ domain ] = www.domain.tld ; // or domain.tld based on your actual domain
}
// Ensure the path is correctly set
$cookie[ path ] = $cookie[ path ] ?? / ;
$browser->driver->manage()->addCookie($cookie);
}
}
}
private function isLoggedIn(Browser $browser) {
// Implement a method to check if the user is already logged in
// Example: Check for a specific element that is visible when logged in
try {
$browser->visit( https://backoffice.domain.tld )
->assertSee( Dashboard );
return true;
} catch (Exception $e) {
return false;
}
}
This will fix your problem.