尝试使用最新的堆栈 SF7、APIPlatform 4 和 JWT 创建 API 项目。
API 运行良好,可将 JWT 令牌生成到 uth URL 中
但总是返回错误:401 无效凭据
在 web 和 stackOverflow 中尝试了很多解决方案,但没有解决这个问题。
可能是特定堆栈出现问题或错误...
感谢您的建议
这些要求已完成:
生成 JWT 密钥
激活 JWT lexik 捆绑到bundles.php
getUserIdentifier() 设置为用户实体
安全.yaml
security:
password_hashers:
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
providers:
app_user_provider:
entity:
class: App\Entity\Users
property: email
firewalls:
dev:
pattern: ^/_(profiler|wdt)
security: false
main:
stateless: true
provider: app_user_provider
json_login:
check_path: auth
username_path: email
password_path: password
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
jwt: ~
access_control:
- { path: ^/$, roles: PUBLIC_ACCESS }
- { path: ^/docs, roles: PUBLIC_ACCESS }
- { path: ^/auth, roles: PUBLIC_ACCESS }
- { path: ^/, roles: IS_AUTHENTICATED_FULLY }
lexik_jwt_authentication.yaml
lexik_jwt_authentication:
secret_key: '%env(resolve:JWT_SECRET_KEY)%'
public_key: '%env(resolve:JWT_PUBLIC_KEY)%'
pass_phrase: '%env(resolve:JWT_PASSPHRASE)%'
路由/api_platform.yaml
api_platform:
resource: .
type: api_platform
prefix: /api
routes.yaml
auth:
path: /auth
methods: ['POST']
controllers:
resource:
path: ../src/Controller/
namespace: App\Controller
type: attribute
UserFixtures.php:
$user1 = new Users();
$user1->setCivility('mr');
$user1->setEmail('[email protected]');
$user1->setRoles(['ROLE_SUPER_ADMIN']);
$hashedPassword = $this->hasher->hashPassword($user1, 'rere-toto');
$user1->setPassword($hashedPassword);
$user1->setUsername('jordy');
$user1->setFirstName('michael');
$user1->setLastName('jordan');
$manager->persist($user1);
$manager->flush();
Users.php(实体)
<?php
namespace App\Entity;
use ApiPlatform\Metadata\ApiResource;
use App\Repository\UsersRepository;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\Mapping\JoinColumn;
use Doctrine\ORM\Mapping\ManyToOne;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
use Symfony\Component\Security\Core\User\UserInterface;
#[ORM\Entity(repositoryClass: UsersRepository::class)]
#[ORM\UniqueConstraint(name: 'UNIQ_IDENTIFIER_EMAIL', fields: ['email'])]
#[UniqueEntity(fields: ['email'], message: 'There is already an account with this email')]
#[ApiResource]
class Users implements UserInterface, PasswordAuthenticatedUserInterface
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
#[ORM\Column(length: 180)]
private ?string $email = null;
#[ORM\Column]
private array $roles = [];
#[ORM\Column(type: 'string')]
private ?string $password = null;
#[ORM\Column(type: 'boolean')]
private bool $isVerified = false;
#[ORM\Column(type: 'string')]
private string $civility;
#[ORM\Column(type: 'string')]
private string $firstName;
#[ORM\Column(type: 'string')]
private string $lastName;
#[ORM\Column(type: 'string')]
private string $username;
#[ORM\Column(type: 'blob', nullable: true)]
private string $picture;
#[ORM\Column(type: 'string', length: 2)]
private string $locale = 'fr';
public function getId(): ?int
{
return $this->id;
}
public function getEmail(): ?string
{
return $this->email;
}
public function setEmail(string $email): static
{
$this->email = $email;
return $this;
}
public function getUserIdentifier(): string
{
return (string) $this->email;
}
public function getRoles(): array
{
$roles = $this->roles;
// guarantee every user at least has ROLE_USER
$roles[] = 'ROLE_USER';
return array_unique($roles);
}
public function setRoles(array $roles): static
{
$this->roles = $roles;
return $this;
}
public function getPassword(): string
{
return $this->password;
}
public function setPassword(string $password): static
{
$this->password = $password;
return $this;
}
public function getCivility(): string
{
return $this->civility;
}
public function setCivility(string $civility): void
{
$this->civility = $civility;
}
public function getFirstName(): string
{
return $this->firstName;
}
public function setFirstName(string $firstName): void
{
$this->firstName = $firstName;
}
public function getLastName(): string
{
return $this->lastName;
}
public function setLastName(string $lastName): void
{
$this->lastName = $lastName;
}
public function getUsername(): string
{
return $this->username;
// return $this->email;
}
public function setUsername(string $username): void
{
$this->username = $username;
}
public function getLocale(): string
{
return $this->locale;
}
public function setLocale(string $locale): void
{
$this->locale = $locale;
}
public function eraseCredentials(): void
{
// If you store any temporary, sensitive data on the user, clear it here
// $this->plainPassword = null;
}
public function getIsVerified(): bool
{
return $this->isVerified;
}
public function setIsVerified(bool $isVerified): static
{
$this->isVerified = $isVerified;
return $this;
}
public function getPicture(): string
{
return $this->picture;
}
public function setPicture(string $picture): void
{
$this->picture = $picture;
}
}
.env
JWT_SECRET_KEY=%kernel.project_dir%/config/jwt/private.pem
JWT_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public.pem
JWT_PASSPHRASE=a0b919dGJxxxxxxcaa29fkh56bxxxxx2fde41f13381b7dac864
处理登录验证的问题。 Lexik 捆绑包 (3.0) 将“user_identity_field”选项删除到其配置文件中。然后它提供用户名(并且在新版本中您无法更改)和电子邮件(使用 api 平台和安全 symfony 引擎配置)之间的验证。
如果您将 lexik 包降级为 2 号版本,您可以检索“user_identity_field”选项并使用“email”值进行设置。
之后一切正常运行。