我正在开发一个API,我已经实现了一个JWT,以使它成为无状态的。我创建了一个AuthController,它在登录信息正确时返回一个JWT。在这里您可以看到生成令牌的返回代码:
/* RETURN MESSAGE */
$body = [
'auth_token' => $jwt,
];
$json = new JsonResponse($body);
$json->setStatusCode(201, "Created"); // Headers
return $json;这是运行身份验证方法时的结果,即取消localhost:8000/authenticate URL。
现在,我需要做的是,当用户试图获得另一个/ URL时,如果他没有在请求的头上传递Bearer令牌,程序就不允许他到达它。但这不管用。该平台始终允许我输入任何URL,而无需在标题中设置授权。
这是我的安全文件,我试图设置这个文件:
security:
# https://symfony.com/doc/current/security/authenticator_manager.html
enable_authenticator_manager: true
# https://symfony.com/doc/current/security.html#c-hashing-passwords
password_hashers:
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
encoders:
App\Entity\ATblUsers:
algorithm: bcrypt
providers:
users_in_memory: { memory: null }
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
# Anonymous property is no longer supported by Symfony. It is commented by now, but it will be deleted in
# future revision:
# anonymous: true
guard:
authenticators:
- App\Security\JwtAuthenticator
lazy: true
provider: users_in_memory
# activate different ways to authenticate
# https://symfony.com/doc/current/security.html#firewalls-authentication
# https://symfony.com/doc/current/security/impersonating_user.html
# switch_user: true
stateless: true
# 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: ^/admin, roles: ROLE_ADMIN }
# - { path: ^/profile, roles: ROLE_USER }最后,这是我的App\Security\JwtAuthenticator
namespace App\Security;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\DependencyInjection\ParameterBag\ContainerBagInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Firebase\JWT\JWT;
use Symfony\Component\Security\Guard\AbstractGuardAuthenticator;
class JwtAuthenticator extends AbstractGuardAuthenticator
{
private $em;
private $params;
public function __construct(EntityManagerInterface $em, ContainerBagInterface $params)
{
$this->em = $em;
$this->params = $params;
}
public function start(Request $request, AuthenticationException $authException = null): JsonResponse
{
$body = [
'message' => 'Authentication Required',
];
return new JsonResponse($body, Response::HTTP_UNAUTHORIZED);
}
public function supports(Request $request): bool
{
return $request->headers->has('Authorization');
}
public function getCredentials(Request $request)
{
return $request->headers->get('Authorization');
}
public function getUser($credentials, UserProviderInterface $userProvider)
{
try{
$credentials = str_replace('Bearer ', '', $credentials);
$jwt = (array) JWT::decode($credentials, $this->params->get('jwt_secret'), ['HS256']);
return $this->em->getRepository('App:ATblUsers')->find($jwt['sub']);
}catch (\Exception $exception){
throw new AuthenticationException($exception->getMessage());
}
}
public function checkCredentials($credentials, UserInterface $user)
{
}
public function onAuthenticationFailure(Request $request, AuthenticationException $exception): JsonResponse
{
return new JsonResponse([
'message' => $exception->getMessage()
], Response::HTTP_UNAUTHORIZED);
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $providerKey)
{
return;
}
public function supportsRememberMe(): bool
{
return false;
}
}我已经看了很多网站和教程,但没有人在做我需要的事情,或者正在实现与我所需要的不匹配的非常基本的功能。几乎所有这些网站都使用Symfony 4来解释这一点,但是我使用的是Symfony 5,所以很多在教程中使用的功能都被废弃了。有人知道我错过了什么吗?
发布于 2021-10-22 10:29:10
您可能缺少access_control在security.yaml中的配置。
security:
# https://symfony.com/doc/current/security/authenticator_manager.html
enable_authenticator_manager: true
# https://symfony.com/doc/current/security.html#c-hashing-passwords
password_hashers:
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
encoders:
App\Entity\ATblUsers:
algorithm: bcrypt
providers:
users_in_memory: { memory: null }
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
# Anonymous property is no longer supported by Symfony. It is commented by now, but it will be deleted in
# future revision:
# anonymous: true
guard:
authenticators:
- App\Security\JwtAuthenticator
lazy: true
provider: users_in_memory
# activate different ways to authenticate
# https://symfony.com/doc/current/security.html#firewalls-authentication
# https://symfony.com/doc/current/security/impersonating_user.html
# switch_user: true
stateless: true
# 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: ^/authenticate, roles: PUBLIC_ACCESS }
- { path: ^/, roles: IS_AUTHENTICATED_FULLY }发布于 2021-10-22 11:27:44
我没有详细地看过您的代码,我只想告诉您,您所做的艰苦工作已经存在于一个维护良好的包中,并且您不需要编写硬代码,我真的邀请您使用它是非常有用的。
发布于 2022-06-28 17:32:57
解决方案: Symfony 6
在我的例子中,我来这里寻找一个Symfony 6解决方案。
我不得不安装Firebase PHP (composer require kreait/firebase-php)
我必须从firebase (项目配置->服务帐户)下载身份验证json文件,以便init
App\Security\JWTAuthenticator:
<?php
namespace App\Security;
use App\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\DependencyInjection\ParameterBag\ContainerBagInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
use Symfony\Component\Cache\Simple\FilesystemCache;
use Kreait\Firebase;
use Firebase\Auth\Token\Exception\InvalidToken;
class JWTAuthenticator extends AbstractAuthenticator
{
private $em;
private $params;
private $projectDirectory;
private $firebase;
public function __construct(string $projectDirectory, EntityManagerInterface $em, ContainerBagInterface $params)
{
$this->projectDirectory = $projectDirectory;
$this->em = $em;
$this->params = $params;
$this->firebase = (new Firebase\Factory())->withServiceAccount($this->projectDirectory.'/firebase-authentication.json');
}
public function start(Request $request, AuthenticationException $authException = null): JsonResponse
{
$body = [
'message' => 'Authentication Required',
];
return new JsonResponse($body, Response::HTTP_UNAUTHORIZED);
}
public function supports(Request $request): bool
{
return $request->headers->has('Authorization');
}
public function getCredentials(Request $request)
{
return $request->headers->get('Authorization');
}
public function onAuthenticationFailure(Request $request, AuthenticationException $exception): JsonResponse
{
return new JsonResponse([
'message' => $exception->getMessage()
], Response::HTTP_UNAUTHORIZED);
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $providerKey): ?Response
{
return null;
}
public function supportsRememberMe(): bool
{
return false;
}
public function authenticate(Request $request): Passport
{
try{
$credentials = str_replace('Bearer ', '', $this->getCredentials($request));
$firebaseAuth = $this->firebase->createAuth();
try {
$verifiedIdToken = $firebaseAuth->verifyIdToken($credentials);
$tokenClaims = $verifiedIdToken->claims();
$sub = $tokenClaims->get('sub');
$email = $tokenClaims->get('email');
if ($verifiedIdToken->isExpired(new \DateTime())) {
throw new AuthenticationException("Token expired.");
}
} catch (Firebase\Exception\AuthException | Firebase\Exception\FirebaseException $e) {
throw new AuthenticationException($e->getMessage());
}
}
catch (\Exception $exception){
throw new AuthenticationException($exception->getMessage());
}
return new SelfValidatingPassport(new UserBadge($email));
}
}我的security.yaml
security:
enable_authenticator_manager: true
password_hashers:
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
App\Entity\User:
algorithm: auto
providers:
app_user_provider:
entity:
class: App\Entity\User
property: email
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
lazy: true
stateless: true
provider: app_user_provider
custom_authenticator: App\Security\JWTAuthenticator
# 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: ^/api/docs, roles: PUBLIC_ACCESS }
- { path: ^/, roles: IS_AUTHENTICATED_FULLY }https://stackoverflow.com/questions/69675036
复制相似问题