Reputation: 5849
Whenever I go to /admin/logout
, I'm correctly redirected to the root of my project but still logged in when I visit /admin/
as I'm not prompted for credentials.
Here is my configuration:
security.yml
security:
firewalls:
admin_area:
pattern: ^/admin
http_basic: ~
stateless: true
switch_user: { role: ROLE_SUPER_ADMIN, parameter: _want_to_be_this_user }
logout: { path: /admin/logout, target: / }
AdminBundle/Resources/config/routing.yml
logout:
pattern: /logout
app/config/routing.yml
admin:
resource: "@AdminBundle/Resources/config/routing.yml"
prefix: /admin
The authorization is still in place as the headers state Authorization:Basic YWRtaW46cEAkJHcwUmQh
so I guess credentials are still provided to the application during the request.
I know there is no proper way to logout from a HTTP Basic Auth
as per this question but maybe Symfony2 allows it?
Upvotes: 7
Views: 6800
Reputation: 7596
The answer of @Niki Van Cleemput doesn't seem to work in all cases. When I tested it, it was OK on Chrome 44 but not on Firefox 48. Here is a solution inspired by HTTP authentication logout via PHP:
The security parameters:
security:
# ... your encoders, role_hierarchy, providers...
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
pattern: ^/
anonymous: ~
stateless: true
http_basic:
realm: "My admin area"
# no logout parameter as it is handled manually
access_control:
- { path: ^/admin, roles: ROLE_ADMIN }
The controller with the "fake" logout action:
<?php
namespace Me\Bundle\CoreBundle\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
/**
* Security stuff.
*/
class SecurityController extends Controller
{
/**
* Logout confirmation.
*
* @Route("/logout", name="logout")
*/
public function logoutAction()
{
return $this->render('@EasyAdmin/default/logout.html.twig'); // change with your template path
}
}
In your layout:
<script type="text/javascript">
function logout() {
var xmlhttp;
if (window.XMLHttpRequest) {
xmlhttp = new XMLHttpRequest();
}
// code for IE
else if (window.ActiveXObject) {
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
if (window.ActiveXObject) {
// IE clear HTTP Authentication
document.execCommand("ClearAuthenticationCache");
window.location.href='{{ path('logout') }}';
} else {
xmlhttp.open("GET", '{{ path('easyadmin') }}', true, "logout", "logout");
xmlhttp.send("");
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4) {window.location.href='{{ path('logout') }}';}
}
}
return false;
}
</script>
Add the logout link:
<a href="#" onclick="logout()"><i class="hidden-xs fa fa-user"></i> Logout</a>
At least it works in both Chrome and Firefox, let me know if it doesn't on other browsers.
Upvotes: 0
Reputation: 151
Once logged in via http auth, your browser will cache and add your login credentials to each subsequent request in the form of a header like this:
Authorization:Basic YWRtaW46YWRtaW4=
When you do a logout, the next request to the server will still hold your http credentials and log you in again.
So the trick is to lose the http credentials on the client side after destroying the session on the server side.
In the past there where some hackidy methods like submitting false credentials or some obscure IE method for deleting the cache. But I don't think these methods still work.
What still works ( I tested the following method with symfony 2.7 and google chrome 45 ) is replying to the client with a HTTP 401 unauthorized response.
Check it out:
Add the following to your logout section in the app/config/security.yml file
logout:
success_handler: logout_listener
To your services configuration app/config/services.yml
logout_listener:
class: AppBundle\LogoutListener
Then create a listener that responds with HTTP 401 unauthorized
<?php
namespace AppBundle;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Http\Logout\LogoutSuccessHandlerInterface;
class LogoutListener implements LogoutSuccessHandlerInterface
{
public function onLogoutSuccess(Request $request)
{
return new Response('', 401);
}
}
After logging out your app will send a 401 to the browser which will think authentication has failed resulting in the auth cache being cleared ( who wants to remember faulty credentials anyway right ) and prompt for your credentials again
Upvotes: 12