完整的配置文件如下所示
我的网站在不同的条目使用2个防护:
lexik_jwt_authentication.jwt_token_authenticator
访问^/api
路由AppSecurityLoginAuthenticator
访问^/secured
路由
JWT认证运行良好,允许用户调用API平台形式的路由,如localhost/api/types
问题在于使用LoginAuthenticator
会话。这是基本的符号配置(使用php bin/console make:auth
自动生成的文件(
当使用正确的用户/密码登录时,警卫将会话保存到app/var/sessions/dev/sess_ras4up86e1c8a1bs9khr5t7scg
当会话被保存和设置时,LoginAuthenticator
触发onAuthenticationSuccess
函数,将用户重定向到路由名称`test。
但是testController
不起作用,将用户重定向到登录页面(302 HTTP code
(。它还在var/log/dev/dev.log
中抛出以下错误:
[2021-07-08 13:07:40] request.INFO: Matched route "app_login". {"route":"app_login","route_parameters":{"_route":"app_login","_controller":"App\Controller\SecurityController::login"},"request_uri":"https://krang.local/login","method":"POST"} []
[2021-07-08 13:07:40] security.DEBUG: Checking for guard authentication credentials. {"firewall_key":"login","authenticators":1} []
[2021-07-08 13:07:40] security.DEBUG: Checking support on guard authenticator. {"firewall_key":"login","authenticator":"App\Security\LoginAuthenticator"} []
[2021-07-08 13:07:40] security.DEBUG: Calling getCredentials() on guard authenticator. {"firewall_key":"login","authenticator":"App\Security\LoginAuthenticator"} []
[2021-07-08 13:07:40] security.DEBUG: Passing guard token information to the GuardAuthenticationProvider {"firewall_key":"login","authenticator":"App\Security\LoginAuthenticator"} []
[2021-07-08 13:07:40] doctrine.DEBUG: SELECT t0.id AS id_1, t0.username AS username_2, t0.password AS password_3, t0.is_active AS is_active_4, t0.roles AS roles_5, t0.customer_id AS customer_id_6 FROM users t0 WHERE t0.username = ? LIMIT 1 ["matthieu"] []
[2021-07-08 13:07:40] security.INFO: Guard authentication successful! {"token":"[object] (Symfony\Component\Security\Guard\Token\PostAuthenticationGuardToken: PostAuthenticationGuardToken(user="matthieu", authenticated=true, roles="ROLE_USER, ROLE_ADMIN"))","authenticator":"App\Security\LoginAuthenticator"} []
[2021-07-08 13:07:40] security.DEBUG: Guard authenticator set success response. {"response":"[object] (Symfony\Component\HttpFoundation\RedirectResponse: HTTP/1.0 302 FoundrnCache-Control: no-cache, privaternDate: Thu, 08 Jul 2021 11:07:40 GMTrnLocation: /secured/backmarketProductsrnrn<!DOCTYPE html>n<html>n <head>n <meta charset="UTF-8" />n <meta http-equiv="refresh" content="0;url='/secured/backmarketProducts'" />nn <title>Redirecting to /secured/backmarketProducts</title>n </head>n <body>n Redirecting to <a href="/secured/backmarketProducts">/secured/backmarketProducts</a>.n </body>n</html>)","authenticator":"App\Security\LoginAuthenticator"} []
[2021-07-08 13:07:40] security.DEBUG: Remember me skipped: it is not configured for the firewall. {"authenticator":"App\Security\LoginAuthenticator"} []
[2021-07-08 13:07:40] security.DEBUG: The "AppSecurityLoginAuthenticator" authenticator set the response. Any later authenticator will not be called {"authenticator":"App\Security\LoginAuthenticator"} []
[2021-07-08 13:07:40] request.INFO: Matched route "test". {"route":"test","route_parameters":{"_route":"test","_controller":"App\Controller\BackMarketController::productsList"},"request_uri":"https://krang.local/secured/backmarketProducts","method":"GET"} []
[2021-07-08 13:07:40] security.DEBUG: Checking for guard authentication credentials. {"firewall_key":"secured","authenticators":1} []
[2021-07-08 13:07:40] security.DEBUG: Checking support on guard authenticator. {"firewall_key":"secured","authenticator":"App\Security\LoginAuthenticator"} []
[2021-07-08 13:07:40] security.DEBUG: Guard authenticator does not support the request. {"firewall_key":"secured","authenticator":"App\Security\LoginAuthenticator"} []
[2021-07-08 13:07:40] security.INFO: An AuthenticationException was thrown; redirecting to authentication entry point. {"exception":"[object] (Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException(code: 0): A Token was not found in the TokenStorage. at /home/matthieu/krang/webservice/vendor/symfony/security-http/Firewall/AccessListener.php:69)"} []
[2021-07-08 13:07:40] security.DEBUG: Calling Authentication entry point. [] []
[2021-07-08 13:07:40] request.INFO: Matched route "app_login". {"route":"app_login","route_parameters":{"_route":"app_login","_controller":"App\Controller\SecurityController::login"},"request_uri":"https://krang.local/login","method":"GET"} []
[2021-07-08 13:07:40] security.DEBUG: Checking for guard authentication credentials. {"firewall_key":"login","authenticators":1} []
[2021-07-08 13:07:40] security.DEBUG: Checking support on guard authenticator. {"firewall_key":"login","authenticator":"App\Security\LoginAuthenticator"} []
[2021-07-08 13:07:40] security.DEBUG: Guard authenticator does not support the request. {"firewall_key":"login","authenticator":"App\Security\LoginAuthenticator"} []
[2021-07-08 13:07:40] security.INFO: Populated the TokenStorage with an anonymous Token. [] []
[2021-07-08 13:07:40] request.INFO: Matched route "_wdt". {"route":"_wdt","route_parameters":{"_route":"_wdt","_controller":"web_profiler.controller.profiler::toolbarAction","token":"ad25b7"},"request_uri":"https://krang.local/_wdt/ad25b7","method":"GET"} []
我们可以看到这个错误:
[2021-07-08 13:07:40] security.DEBUG: Guard authenticator does not support the request. {"firewall_key":"secured","authenticator":"App\Security\LoginAuthenticator"} []
[2021-07-08 13:07:40] security.INFO: An AuthenticationException was thrown; redirecting to authentication entry point. {"exception":"[object] (Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException(code: 0): A Token was not found in the TokenStorage. at /home/matthieu/krang/webservice/vendor/symfony/security-http/Firewall/AccessListener.php:69)"} []
Guard验证器不支持请求
这意味着什么?我给你一些有用的代码来结账:
security.yaml:(完整文件(
security:
encoders:
AppEntityUser:
algorithm: auto
role_hierarchy:
ROLE_USER : "ROLE_USER"
ROLE_ADMIN : "ROLE_ADMIN"
ROLE_SUPERADMIN : "ROLE_SUPERADMIN"
providers:
entity_provider:
entity:
class: AppEntityUser
property: username
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
login:
pattern: ^/login
stateless: true
anonymous: true
json_login:
check_path: /login_check
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
guard:
authenticators:
- AppSecurityLoginAuthenticator
logout:
path: app_logout
# where to redirect after logout
# target: app_any_route
docs:
pattern: ^/docs
stateless: true
anonymous: true
secured:
pattern: ^/secured
stateless: true
provider: entity_provider
guard:
authenticators:
- AppSecurityLoginAuthenticator
api:
pattern: ^/api
stateless: true
anonymous: false
provider: entity_provider
guard:
authenticators:
- lexik_jwt_authentication.jwt_token_authenticator
access_control:
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api, roles: IS_AUTHENTICATED_FULLY }
- { path: ^/docs, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/secured, roles: IS_AUTHENTICATED_FULLY }
安全控制器:(与默认值保持不变(
class SecurityController extends AbstractController
{
/**
* @Route("/login", name="app_login")
*/
public function login(AuthenticationUtils $authenticationUtils): Response
{
if ($this->getUser()) {
die();
}
// get the login error if there is one
$error = $authenticationUtils->getLastAuthenticationError();
// last username entered by the user
$lastUsername = $authenticationUtils->getLastUsername();
return $this->render('security/login.html.twig', ['last_username' => $lastUsername, 'error' => $error]);
}
/**
* @Route("/logout", name="app_logout")
*/
public function logout()
{
throw new LogicException('This method can be blank - it will be intercepted by the logout key on your firewall.');
}
}
LoginAuthenticator:(src/Security/LoginAuthenticator.php(
class LoginAuthenticator extends AbstractFormLoginAuthenticator implements PasswordAuthenticatedInterface
{
use TargetPathTrait;
public const LOGIN_ROUTE = 'app_login';
private $entityManager;
private $urlGenerator;
private $csrfTokenManager;
private $passwordEncoder;
public function __construct(EntityManagerInterface $entityManager, UrlGeneratorInterface $urlGenerator, CsrfTokenManagerInterface $csrfTokenManager, UserPasswordEncoderInterface $passwordEncoder)
{
$this->entityManager = $entityManager;
$this->urlGenerator = $urlGenerator;
$this->csrfTokenManager = $csrfTokenManager;
$this->passwordEncoder = $passwordEncoder;
}
public function supports(Request $request)
{
return self::LOGIN_ROUTE === $request->attributes->get('_route')
&& $request->isMethod('POST');
}
public function getCredentials(Request $request)
{
$credentials = [
'username' => $request->request->get('username'),
'password' => $request->request->get('password'),
'csrf_token' => $request->request->get('_csrf_token'),
];
$request->getSession()->set(
Security::LAST_USERNAME,
$credentials['username']
);
return $credentials;
}
public function getUser($credentials, UserProviderInterface $userProvider)
{
$token = new CsrfToken('authenticate', $credentials['csrf_token']);
if (!$this->csrfTokenManager->isTokenValid($token)) {
throw new InvalidCsrfTokenException();
}
$user = $this->entityManager->getRepository(User::class)->findOneBy(['username' => $credentials['username']]);
if (!$user) {
throw new UsernameNotFoundException('Username could not be found.');
}
return $user;
}
public function checkCredentials($credentials, UserInterface $user)
{
return $this->passwordEncoder->isPasswordValid($user, $credentials['password']);
}
/**
* Used to upgrade (rehash) the user's password automatically over time.
*/
public function getPassword($credentials): ?string
{
return $credentials['password'];
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
if ($targetPath = $this->getTargetPath($request->getSession(), $providerKey)) {
return new RedirectResponse($targetPath);
}
return new RedirectResponse($this->urlGenerator->generate('test'));
}
protected function getLoginUrl()
{
return $this->urlGenerator->generate(self::LOGIN_ROUTE);
}
}
BackMarketController(只是一个函数(验证成功时调用的函数
/**
* @return JsonResponse
* @Route("/secured/backmarketProducts", name="test")
*/
public function productsList(Request $request)
{
return $this->render('back_market/backmarketProducts.html.twig');
}
关于网络服务器:
- Apache2
- Debian 8
- 使用HTTPS
- Symfony 4.4
我当然可以给你更多的信息,只要问一下就行了。
我在其他类似主题上的尝试:
- Symfony 4登录Guard验证器错误(将会话信息从默认值保存到其他位置(
- 更新项目组件
- Symfony 4登录表单:身份验证成功,但重定向后身份验证立即丢失(将
EquatableInterface
添加到User
实体( - 在重定向之前杀死
onAuthenticationSuccess
在探查器上显示会话已创建但无法遵循重定向(查看上面的错误(
更新1(3天后(
我找到了一种允许jwt代币和securityauthenticator协同工作的方法。
这就是安全性
security:
encoders:
AppEntityUser:
algorithm: auto
role_hierarchy:
ROLE_USER : "ROLE_USER"
ROLE_ADMIN : "ROLE_ADMIN"
ROLE_SUPERADMIN : "ROLE_SUPERADMIN"
providers:
entity_provider:
entity:
class: AppEntityUser
property: username
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
anonymous: true
guard:
entry_point: lexik_jwt_authentication.jwt_token_authenticator
authenticators:
- AppSecuritySecurityAuthenticator
- lexik_jwt_authentication.jwt_token_authenticator
logout:
path: app_logout
json_login:
check_path: /login_check
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
login:
pattern: ^/login
stateless: true
anonymous: true
json_login:
check_path: /login_check
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
docs:
pattern: ^/docs
stateless: true
anonymous: true
api:
pattern: ^/api
stateless: true
anonymous: false
provider: entity_provider
guard:
authenticators:
- lexik_jwt_authentication.jwt_token_authenticator
secured:
pattern: ^/secured
anonymous: false
guard:
authenticators:
- AppSecuritySecurityAuthenticator
logout:
path: app_logout
access_control:
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api, roles: IS_AUTHENTICATED_FULLY }
- { path: ^/docs, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/secured, roles: IS_AUTHENTICATED_FULLY }
我认为该块解决了问题,symfony安全竞争对手在main防火墙上声明了两个保护,默认情况下使用jwt。
为了使用基本的symfony身份验证系统(securityAuthentificator
(,我刚刚添加了一个安全的防火墙,提供SecurityAuthenticator
有没有一个好的方法来处理安全问题?这个把戏看起来合法吗?我不确定我能提供一个好的解决方案。
似乎没有人能帮我。无论如何,我自己解决了问题。
有我的全部功能安全。yaml:
该配置正在发挥作用,使symfony能够使用带有JWT令牌的API PLATEFORM,并将用户登录到一个简单的后台应用程序。
security:
encoders:
AppEntityUser:
algorithm: auto
role_hierarchy:
ROLE_USER : "ROLE_USER"
ROLE_ADMIN : "ROLE_ADMIN"
ROLE_SUPERADMIN : "ROLE_SUPERADMIN"
providers:
entity_provider:
entity:
class: AppEntityUser
property: username
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
anonymous: true
guard:
entry_point: lexik_jwt_authentication.jwt_token_authenticator
authenticators:
- AppSecuritySecurityAuthenticator
- lexik_jwt_authentication.jwt_token_authenticator
logout:
path: app_logout
json_login:
check_path: /login_check
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
login:
pattern: ^/login
stateless: true
anonymous: true
json_login:
check_path: /login_check
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
docs:
pattern: ^/docs
stateless: true
anonymous: true
api:
pattern: ^/api
stateless: true
anonymous: false
provider: entity_provider
guard:
authenticators:
- lexik_jwt_authentication.jwt_token_authenticator
secured:
pattern: ^/secured
anonymous: false
guard:
authenticators:
- AppSecuritySecurityAuthenticator
logout:
path: app_logout
access_control:
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api, roles: IS_AUTHENTICATED_FULLY }
- { path: ^/docs, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/secured, roles: IS_AUTHENTICATED_FULLY }