无法在Symfony 5中创建JWT

hjzp0vay  于 2023-03-03  发布在  其他
关注(0)|答案(1)|浏览(149)

我想在我的应用程序中创建JWT。从以下链接开始使用Symfony文档:https://symfony.com/bundles/LexikJWTAuthenticationBundle/current/index.html#about-token-expirationhttps://symfony.com/doc/current/security.html#json-login我找不到任何解决方案。
我的代码如下所示:* * 控制器方法:**

#[Route('api/login', name: 'api_login')]
    public function loginUser(Request $request,
                              JWTTokenManagerInterface $tokenManager
                             ): JsonResponse
    {
        $credentials = json_decode($request->getContent(), true);

        if (!isset($credentials['username'], $credentials['password']) || !$credentials)
        {
            return new JsonResponse('Missing credentials', Response::HTTP_UNAUTHORIZED);
        }

        $username = $credentials['username'];
        $password = $credentials['password'];

        $user = $this->repository->findOneBy(['username' => $username]);

        if (!$user instanceof UserInterface || !$this->passwordHasher->isPasswordValid($user, $password))
        {
            return new JsonResponse('Invalid credentials', Response::HTTP_UNAUTHORIZED);
        }

        $token = $tokenManager->create($user);

        return new JsonResponse($user->getUserIdentifier() . $token);
    }
    • 路线. yaml**
login:
    path: /api/login
    • 安全性. yaml**
security:
    password_hashers:
        Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
    providers:
        app_user_provider:
            entity:
                class: App\Entity\User
                property: username
    firewalls:
        login:
            pattern: ^/api/login
            stateless: true
            json_login:
                check_path: /api/login
                success_handler: lexik_jwt_authentication.handler.authentication_success
                failure_handler: lexik_jwt_authentication.handler.authentication_failure
        api:
            pattern: ^/api
            stateless: true
            jwt: ~
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        main:
            lazy: true
            provider: app_user_provider

    access_control:
         - { path: ^/api/register, roles: PUBLIC_ACCESS }
         - { path: ^/api/login, roles: PUBLIC_ACCESS }
         - { path: ^/api, roles: IS_AUTHENTICATED_FULLY }

when@test:
    security:
        password_hashers:
            Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface:
                algorithm: auto
                cost: 4 
                time_cost: 3 
                memory_cost: 10
  • .环境*
JWT_SECRET_KEY=%kernel.project_dir%/config/jwt/private.pem
JWT_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public.pem
JWT_PASSPHRASE=9c32a9b40d2606c7aed87e3eb8642bd7
    • lexik_jwt_身份验证. yaml**
lexik_jwt_authentication:
    secret_key: '%env(resolve:JWT_SECRET_KEY)%'
    public_key: '%env(resolve:JWT_PUBLIC_KEY)%'
    pass_phrase: '%env(JWT_PASSPHRASE)%'
    token_ttl: 3600
    • 那是错误**
<!-- Unable to create a signed JWT from the given configuration. (500 Internal Server Error) -->

这就是我得到的全部。有人能从我的网站看到任何错误或可以解决吗?

u5rb5r59

u5rb5r591#

如果您有自定义身份验证工作流,则可以使用custom authenticator
下面是JWT的一个自定义示例。

<?php

declare(strict_types=1);

namespace App\Security;

use App\Entity\Account;
use App\Repository\AccountRepository;
use Doctrine\ORM\NonUniqueResultException;
use JetBrains\PhpStorm\ArrayShape;
use Lexik\Bundle\JWTAuthenticationBundle\Services\JWTTokenManagerInterface;
use Symfony\Component\HttpFoundation\{Cookie, RedirectResponse, Request};
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Http\Authenticator\AbstractLoginFormAuthenticator;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\{CsrfTokenBadge, UserBadge};
use Symfony\Component\Security\Http\Authenticator\Passport\Credentials\PasswordCredentials;
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
use Symfony\Component\Security\Http\Util\TargetPathTrait;

class AppAuthenticator extends AbstractLoginFormAuthenticator
{
    use TargetPathTrait;

    public const JWT_COOKIE_NAME = 'BEARER';

    public function __construct(
        private readonly AccountRepository $repository,
        private readonly UrlGeneratorInterface $router,
        private readonly JWTTokenManagerInterface $jwtTokenManager,
        private readonly string $jwtTtlInSeconds,
        private readonly string $hostname
    ) {
    }

    /**
     * {@inheritDoc}
     */
    protected function getLoginUrl(Request $request): string
    {
        return $this->router->generate('login');
    }

    /**
     * @throws  NonUniqueResultException
     */
    private function getUserByIdentifier(string $userIdentifier): ?Account
    {
        return $this->repository->loadUserByIdentifier($userIdentifier);
    }

    /**
     * {@inheritDoc}
     */
    public function authenticate(Request $request): Passport
    {
        $credentials = self::getCredentials($request);

        return new Passport(
            new UserBadge(
                $credentials['identifier'],
                function (string $userIdentifier): ?Account {
                    return $this->getUserByIdentifier($userIdentifier);
                }
            ),
            new PasswordCredentials($credentials['password']),
            [new CsrfTokenBadge('authenticate', $credentials['csrf_token'])]
        );
    }

    /**
     * @return  array{identifier: string, password: string, csrf_token: string}
     */
    #[ArrayShape([
        'identifier' => 'string',
        'password' => 'string',
        'csrf_token' => 'string',
    ])]
    private static function getCredentials(Request $request): array
    {
        $credentials = [
            'identifier' => (string) $request->request->get('_identifier'),
            'password' => (string) $request->request->get('_password'),
            'csrf_token' => (string) $request->request->get('_csrf_token'),
        ];

        $request->getSession()->set(
            Security::LAST_USERNAME,
            $credentials['identifier']
        );

        return $credentials;
    }

    /**
     * {@inheritDoc}
     *
     * @throws  NonUniqueResultException
     * @throws  \Exception  when the JWT_TTL_IN_SECONDS cannot be parsed as an
     *                      interval
     */
    public function onAuthenticationSuccess(
        Request $request,
        TokenInterface $token,
        string $firewallName
    ): RedirectResponse {
        $user = $this->getUserByIdentifier(self::getCredentials($request)['identifier']);

        if (!$user) {
            throw new \RuntimeException('Unable to find the user corresponding to identifier');
        }

        $jwtCookie = Cookie::create(self::JWT_COOKIE_NAME)
            ->withExpires((new \DateTimeImmutable())->add(new \DateInterval('PT'.$this->jwtTtlInSeconds.'S')))
            ->withValue($this->jwtTokenManager->create($user))
            ->withDomain($this->hostname)
            ->withPath('/')
            ->withSecure()
        ;

        if ($targetPath = $this->getTargetPath($request->getSession(), $firewallName)) {
            $response = new RedirectResponse($targetPath);
        } else {
            $response = new RedirectResponse($this->router->generate('root'));
        }

        $response->headers->setCookie($jwtCookie);

        return $response;
    }
}

然后在config/services.yaml中:

services:
    _defaults:
        bind:
            $jwtTtlInSeconds: '%env(resolve:JWT_TTL_IN_SECONDS)%'
            $hostname: '%env(resolve:APP_HOST)%'

然后在.env

JWT_TTL_IN_SECONDS=3600
APP_HOST="yourdomain"

不要忘记在config/packages/security.yaml中注册您的验证器:

security:
  # ...
  firewalls:
    # ...
    main:
      # ...
      stateless: true
      jwt: ~

      custom_authenticators:
        - App\Security\AppAuthenticator

相关问题