在会话到期时响应HTTP_UNAUTHORIZED / Redirect

时间:2016-12-15 12:01:01

标签: php symfony security session silex

在我的应用程序中,我在 routes.php 文件中定义了 before() 挂钩:

$app->before(function(Request $request) use($app) {

    $authAnon = $app['security']->isGranted('IS_AUTHENTICATED_ANONYMOUSLY');

    if(!$request->getSession()->get('username') && $authAnon) {

        if($request->isXmlHttpRequest()) {
            // return 401/HTTP_UNAUTHORIZED response
            $response = new Response();
            $response->setStatusCode(Response::HTTP_UNAUTHORIZED);
            $response->headers->set('Reason', 'SESSION_EXPIRED');
            $response->headers->set('WWW-Authenticate', 'MyAuthScheme realm="app:login"');
            return $response;
        }

        return new RedirectResponse('login', 301);

    }

}

但这会导致 $app['security'] 无法找到/定义:

  Container.php第96行中的

InvalidArgumentException :未定义标识符“security”。

我的安全设置如下所示:

$app->register(new Silex\Provider\SecurityServiceProvider(), array(
    'security.firewalls' => array(
        'login' => array(
            'pattern' => '^/login$',
        ),
        'secured' => array(
            'pattern' => '^.*$',
            'form' => array('login_path' => '/login', 'check_path' => '/login_check'),
            'logout' => array('logout_path' => '/logout', 'invalidate_session' => true),
            'users' => array(
                'admin' => array('ROLE_ADMIN', 'hashed_pwd'),
                'user' => array('ROLE_USER', 'hashed_pwd'),
            ),
        ),
    )
));

$app['security.role_hierarchy'] = array(
    'ROLE_ADMIN' => array('ROLE_USER'),
);

$app['security.access_rules'] = array(
    array('^/admin', 'ROLE_ADMIN'),
    array('^.*$', ['ROLE_USER']),
);

会话的顺序&安全提供商的注册情况如下:

$config_path = __DIR__.'/../app/config/';
require_once $config_path.'session.php';
require_once $config_path.'security.php';
require_once $config_path.'routes/routes.php';

$app->run();

我做错了什么?

修改

请看下面的答案,看看我最终得到了什么。

3 个答案:

答案 0 :(得分:1)

{@ 1}}服务已弃用,将从Silex 2.0中删除。如果要检查用户的角色,则需要security服务。

security.authorization_checker

由于您使用的是$authAnon = $app['security.authorization_checker']->isGranted('IS_AUTHENTICATED_ANONYMOUSLY'); (不稳定)版本,因此您需要注意这些事情,或者使用稳定版本。

答案 1 :(得分:1)

我的猜测是您现在正在使用Symfony安全组件的版本> = 2.6+,因此根据Silex docs,您无法直接使用服务安全性(如在$app['security']),您必须使用授权检查程序服务($app['security.authorization_checker']):

<?php

$app->before(function(Request $request) use($app) {

  // This won't work with Symfony Security Component < 2.6
  // $authAnon = $app['security']->isGranted('IS_AUTHENTICATED_ANONYMOUSLY');

  // Under Symfony 2.6+
  $authAnon = $app['security.authorization_checker']->isGranted('IS_AUTHENTICATED_ANONYMOUSLY');
  // ...
}

答案 2 :(得分:0)

这是我最终想出的:

if($request->headers->has('XHR-Request')) {

    $isAuthFully = $app['security.authorization_checker']->isGranted('IS_AUTHENTICATED_FULLY');

    if(!$isAuthFully and $request->get('_route') !== 'login') {

        $response = new Response();
        $response->setStatusCode(Response::HTTP_UNAUTHORIZED);
        $response->headers->set('Login-Redirect', '');
        $response->headers->set('WWW-Authenticate', 'AppAuthScheme realm="application:login"');

        return $response;

    }
}

我在客户端添加了自定义XHR-Request标头:

angular.module('documentsCatalogApp', []).config(httpConfig);

httpConfig.$inject = ['$httpProvider'];
function httpConfig($httpProvider) {
    $httpProvider.defaults.headers.common['XHR-Request'] = '';
}

Symfony的 getRequest()->isXmlHttpRequest() 依赖于 X-Requested-With 标头,可能会被浏览器删除,至少我看过关于 Firefox 的报告。

然后我添加了拦截器:

// mount the config / interceptor to your Angular application
// .config(xhrLoginRedirectInterceptorConfig)
// .factory('xhrLoginRedirectInterceptor', xhrLoginRedirectInterceptor)

xhrLoginRedirectInterceptorConfig.$inject = ['$httpProvider'];
function xhrLoginRedirectInterceptorConfig($httpProvider) {
    $httpProvider.interceptors.push('xhrLoginRedirectInterceptor');
}

xhrLoginRedirectInterceptor.$inject = ['$q', '$window'];
function xhrLoginRedirectInterceptor($q, $window) {

    return {

        request: function(request) { return request; },
        response: function(response) { return response; },

        responseError: function(response) {

            var headersList = response.headers();
            var loginRequired = headersList && headersList.hasOwnProperty('Login-Redirect');

            if(response.status === 401 && loginRequired) {

                var url = "http://" + $window.location.host + baseUrl + "/login";
                $window.location.href = url;

            }

            return $q.reject(response);

        }

    }

}

<强>参考

  1. https://stackoverflow.com/a/22681873/532675
  2. https://github.com/angular/angular.js/issues/11008
  3. https://stackoverflow.com/a/30889331/532675