Symfony4 + jwt-auth rescipe always return {"code":401,"message":"Bad credentials"}
Symfony4 + jwt-auth rescipe always return {"code":401,"message":"Bad credentials"}
我安装了一个 Symfony4,其中安装了一些与 Flex 一起安装的常用包
- 制作
- jwt-auth
- 注解
- 行为
- phpunit
- 服务器
我有这个路由文件:
api_login_check:
path: /api/login_check
我有这样的配置:
security:
encoders:
App\Security\User: plaintext
providers:
app.provider:
id: App\Security\UserProvider
firewalls:
login:
pattern: ^/api/login
stateless: true
anonymous: true
provider: app.provider
form_login:
check_path: /api/login_check
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
require_previous_session: false
api:
pattern: ^/api
stateless: true
provider: app.provider
guard:
authenticators:
- lexik_jwt_authentication.jwt_token_authenticator
access_control:
- { path: ^/api/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api, roles: IS_AUTHENTICATED_FULLY }
和这个用户:
<?php
namespace App\Security;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\EquatableInterface;
class User implements UserInterface, EquatableInterface
{
private $username;
private $password;
private $salt;
private $roles;
public function __construct($username, $password, $salt, array $roles)
{
$this->username = $username;
$this->password = $password;
$this->salt = $salt;
$this->roles = $roles;
}
public function getRoles()
{
return $this->roles;
}
public function getPassword()
{
return $this->password;
}
public function getSalt()
{
return $this->salt;
}
public function getUsername()
{
return $this->username;
}
public function eraseCredentials()
{
}
public function isEqualTo(UserInterface $user)
{
if (!$user instanceof User) {
return false;
}
if ($this->password !== $user->getPassword()) {
return false;
}
if ($this->salt !== $user->getSalt()) {
return false;
}
if ($this->username !== $user->getUsername()) {
return false;
}
return true;
}
}
最后这个用户提供商:
<?php
namespace App\Security;
use App\Security\User;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
class UserProvider implements UserProviderInterface
{
public function loadUserByUsername($username)
{
$username = 'senso';
$password = 'rario';
$salt = 'sale';
$roles = ['ROLE_ADMIN'];
return new User($username, $password, $salt, $roles);
throw new UsernameNotFoundException(
sprintf('Username "%s" does not exist.', $username)
);
}
public function refreshUser(UserInterface $user)
{
if (!$user instanceof User) {
throw new UnsupportedUserException(
sprintf('Instances of "%s" are not supported.', get_class($user))
);
}
return $this->loadUserByUsername($user->getUsername());
}
public function supportsClass($class)
{
return User::class === $class;
}
}
当我运行
curl -X POST http://localhost:8000/api/login_check -d _username=senso -d _password=rario
{"code":401,"message":"Bad credentials"}
我总是得到
{"code":401,"message":"Bad credentials"}
我的问题是:
- 如何解决这个问题?
- 为什么从未调用 UserProvider::loadUserByUsername()?
如果您使用 PlaintextPasswordEncoder
并为您的 User
class 提供 salt
,那么您的 User
的 getPassword
方法应该 return plain_password{salt}
.
在这种情况下,
$username = 'senso';
$password = 'rario{sale}';
$salt = 'sale';
$roles = ['ROLE_ADMIN'];
return new User($username, $password, $salt, $roles);
或
$username = 'senso';
$password = 'rario';
$salt = '';
$roles = ['ROLE_ADMIN'];
return new User($username, $password, $salt, $roles);
用起来没问题。
我安装了一个 Symfony4,其中安装了一些与 Flex 一起安装的常用包
- 制作
- jwt-auth
- 注解
- 行为
- phpunit
- 服务器
我有这个路由文件:
api_login_check:
path: /api/login_check
我有这样的配置:
security:
encoders:
App\Security\User: plaintext
providers:
app.provider:
id: App\Security\UserProvider
firewalls:
login:
pattern: ^/api/login
stateless: true
anonymous: true
provider: app.provider
form_login:
check_path: /api/login_check
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
require_previous_session: false
api:
pattern: ^/api
stateless: true
provider: app.provider
guard:
authenticators:
- lexik_jwt_authentication.jwt_token_authenticator
access_control:
- { path: ^/api/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api, roles: IS_AUTHENTICATED_FULLY }
和这个用户:
<?php
namespace App\Security;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\EquatableInterface;
class User implements UserInterface, EquatableInterface
{
private $username;
private $password;
private $salt;
private $roles;
public function __construct($username, $password, $salt, array $roles)
{
$this->username = $username;
$this->password = $password;
$this->salt = $salt;
$this->roles = $roles;
}
public function getRoles()
{
return $this->roles;
}
public function getPassword()
{
return $this->password;
}
public function getSalt()
{
return $this->salt;
}
public function getUsername()
{
return $this->username;
}
public function eraseCredentials()
{
}
public function isEqualTo(UserInterface $user)
{
if (!$user instanceof User) {
return false;
}
if ($this->password !== $user->getPassword()) {
return false;
}
if ($this->salt !== $user->getSalt()) {
return false;
}
if ($this->username !== $user->getUsername()) {
return false;
}
return true;
}
}
最后这个用户提供商:
<?php
namespace App\Security;
use App\Security\User;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
class UserProvider implements UserProviderInterface
{
public function loadUserByUsername($username)
{
$username = 'senso';
$password = 'rario';
$salt = 'sale';
$roles = ['ROLE_ADMIN'];
return new User($username, $password, $salt, $roles);
throw new UsernameNotFoundException(
sprintf('Username "%s" does not exist.', $username)
);
}
public function refreshUser(UserInterface $user)
{
if (!$user instanceof User) {
throw new UnsupportedUserException(
sprintf('Instances of "%s" are not supported.', get_class($user))
);
}
return $this->loadUserByUsername($user->getUsername());
}
public function supportsClass($class)
{
return User::class === $class;
}
}
当我运行
curl -X POST http://localhost:8000/api/login_check -d _username=senso -d _password=rario {"code":401,"message":"Bad credentials"}
我总是得到
{"code":401,"message":"Bad credentials"}
我的问题是:
- 如何解决这个问题?
- 为什么从未调用 UserProvider::loadUserByUsername()?
如果您使用 PlaintextPasswordEncoder
并为您的 User
class 提供 salt
,那么您的 User
的 getPassword
方法应该 return plain_password{salt}
.
在这种情况下,
$username = 'senso';
$password = 'rario{sale}';
$salt = 'sale';
$roles = ['ROLE_ADMIN'];
return new User($username, $password, $salt, $roles);
或
$username = 'senso';
$password = 'rario';
$salt = '';
$roles = ['ROLE_ADMIN'];
return new User($username, $password, $salt, $roles);
用起来没问题。