У меня есть приложение Symfony с двумя основными разделами. / (все под корнем, например, /userProfile) и /api/ (все под маршрутом /api, например, /api/userInfo/3).
Я использую Twig для рендеринга реальных страниц под root и простой JsonResponse для рендеринга всего под /api. В настоящее время, когда пользователь пытается получить доступ к любой странице/ресурсу, не войдя в систему, он перенаправляется на /login, а затем на запрошенную страницу/ресурс.
Я бы хотел изменить это поведение для всех ресурсов под /api. Что я хотел бы сделать /api/whatever, так это либо вернуть запрошенный ресурс (если вы вошли в систему), либо вернуть 401, если вы не вошли в систему. Я хотел бы продолжать перенаправлять на /login для всех других маршрутов.
(ПРИМЕЧАНИЕ: маршруты /api не являются «RESTful» API-маршрутами как таковыми. Это «внутренние» API-маршруты, которые пользовательский интерфейс использует для запроса данных, необходимых для отображения различных страниц. Поэтому можно с уверенностью предположить, что пользователь вошел бы в систему. через обычную форму входа до того, как их клиент запросит один из этих маршрутов.)
Вот мой security.yaml:
security:
providers:
db_provider:
id: database_user_provider
encoders:
App\Utility\Security\DatabaseUser: bcrypt
access_decision_manager:
strategy: unanimous
allow_if_all_abstain: false
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
pattern: ^/
context: main
form_login:
provider: db_provider
login_path: login
check_path: process_login
default_target_path: manage
use_referer: true
failure_handler: App\Utility\Security\AuthenticationFailureHandler
user_checker: App\Utility\Security\UserChecker
anonymous: ~
logout:
path: logout
target: login
access_denied_handler: App\Utility\Security\AccessDeniedHandler #Turn this off in dev.
# Easy way to control access for large sections of your site
# Note: Only the *first* access control that matches will be used
access_control:
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/forgot, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/%app.locales%, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/, roles: ROLE_USER }
Я попытался добавить новый контекст брандмауэра api:
api:
pattern: ^/api
context: main
# If I don't include this (from "main" firewall), I get an error stating no UserAuthenticationListener has been provided for secuirty.firewall.api.
form_login:
provider: db_provider
login_path: login
check_path: process_login
use_referer: true
failure_handler: App\Utility\Security\AuthenticationFailureHandler
Symfony жалуется, если я не включаю login_path и check_path.
Итак, как я могу сказать Symfony просто потерпеть неудачу и вернуть 401, когда пользователь не вошел в систему (или срок действия сеанса истек), когда (и только когда) они обращаются к маршруту под /api?
Спасибо.






я бы использовал аннотацию @Security https://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/security.html
Добавьте путь ^/api с разрешенными ролями в разделе access_control https://symfony.com/doc/current/security.html#add-code-to-deny-access
Чтобы это заработало, переместите брандмауэр api выше main.
Затем мы можем настроить его на security.yaml со следующей структурой:
api:
pattern: ^/api
context: main
stateless: false
anonymous: true
guard:
authenticators:
- App\Security\ApiAuthenticator
provider: db_provider
Еще нам нужна реализация AuthenticatorInterface. например App\Security\ApiAuthenticator
Нам нужно только реализовать следующие два метода из интерфейса:
start и supports
public function start(Request $request, AuthenticationException $authException = null)
{
return new Response('', Response::HTTP_UNAUTHORIZED);
}
public function supports(Request $request)
{
return false;
}
Примечание: Приведенная выше реализация была протестирована на Symfony 4 (4.3)
Вот так выглядит моя охрана. Он работает так, как вы хотели, просто я использую OAuth
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
oauth_token:
pattern: ^/oauth/v2/token
security: false
oauth_authorize:
pattern: ^/oauth/v2/auth
form_login:
provider: fos_userbundle
check_path: /oauth/v2/auth_login_check
login_path: /oauth/v2/auth_login
use_referer: true
api:
pattern: ^/api
fos_oauth: true
stateless: true
anonymous: false
main:
pattern: ^/
form_login:
provider: fos_userbundle
csrf_token_generator: security.csrf.token_manager
logout: true
anonymous: true
guard:
provider: fos_userbundle
authenticators:
- App\Security\GoogleAuthenticator
- App\Security\FacebookAuthenticator
entry_point: App\Security\LoginFormAuthenticator