如标题所述,我们将使用API平台和LexikjwtauthenticationBundle共同创建如此简单的JWT身份验证。当然使用我们可爱的学说用户提供商。
关于与JWT的Symfony的在线教程太多,有关API平台的教程。但是,他们中的大多数人确实没有帮助,或者它们很短,我发现其中大多数都缺少很多东西。他们甚至不说您需要首先知道一些概念,最后您发现如此多的令人困惑的开发人员。
或者他们只是提到API平台名称,您输入了,这主要是关于Symfony的。老实说,这是有道理的,因为API平台社区太小了,而且实际上是基于Symfony,因此Symfony社区已经问并解决了大多数问题,因此我们很幸运,它是如此大的社区:)。
我希望这将是不同的,如果您有任何疑问或更新,将不胜感激。同样,任何问题都会尝试回答所有问题。
我安装它的最佳方法是使用git存储库,或从github下载API平台作为.zip文件。
$ git clone https://github.com/api-platform/api-platform.git apiplatform-user-auth
$ cd apiplatform-user-auth现在,首先,整个API平台都在特定端口上运行,因此您需要确保此端口是免费的,并且什么也没有听。
$ sudo lsof -nP | grep LISTEN $ sudo kill -9 $PROCESS_NUMBER docker-compose pulldocker-compose up -d $ docker-compose down
$ COMPOSE_HTTP_TIMEOUT=120 docker-compose up -ddocker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6389d8efb6a0 apiplatform-user-auth_h2-proxy " nginx -g 'daemon of… " About a minute ago Up About a minute 0.0.0.0:443-444- > 443-444/tcp, 80/tcp, 0.0.0.0:8443-8444- > 8443-8444/tcp apiplatform-user-auth_h2-proxy_1_a012bc894b6c
a12ff2759ca4 quay.io/api-platform/varnish " docker-varnish-entr… " 2 minutes ago Up 2 minutes 0.0.0.0:8081- > 80/tcp apiplatform-user-auth_cache-proxy_1_32d747ba8877
6c1d29d1cbdd quay.io/api-platform/nginx " nginx -g 'daemon of… " 2 minutes ago Up 2 minutes 0.0.0.0:8080- > 80/tcp apiplatform-user-auth_api_1_725cd9549081
62f69838dacb quay.io/api-platform/php " docker-entrypoint p… " 2 minutes ago Up 2 minutes 9000/tcp apiplatform-user-auth_php_1_cf09d32c3120
381384222af5 dunglas/mercure " ./mercure " 2 minutes ago Up 2 minutes 443/tcp, 0.0.0.0:1337- > 80/tcp apiplatform-user-auth_mercure_1_54363c253a34
783565efb2eb postgres:10-alpine " docker-entrypoint.s… " 2 minutes ago Up 2 minutes 0.0.0.0:5432- > 5432/tcp apiplatform-user-auth_db_1_8da243ca2865
1bc8e386bf02 quay.io/api-platform/client " /bin/sh -c 'yarn st… " 2 minutes ago Up About a minute 0.0.0.0:80- > 3000/tcp apiplatform-user-auth_client_1_1c413b4e4a5e
c22bef7a0b3f quay.io/api-platform/admin " /bin/sh -c 'yarn st… " 2 minutes ago Up About a minute 0.0.0.0:81- > 3000/tcp apiplatform-user-auth_admin_1_cfecc5c6b442$ docker-compose exec php composer require doctrine maker$ docker-compose exec php bin/console make:user
The name of the security user class (e.g. User) [User]:
> Users
Do you want to store user data in the database (via Doctrine) ? (yes/no) [yes]:
>
Enter a property name that will be the unique " display " name for the user (e.g. email, username, uuid) [email]:
> email
Will this app need to hash/check user passwords ? Choose No if passwords are not needed or will be checked/hashed by some other system (e.g. a single sign-on server).
Does this app need to hash/check user passwords ? (yes/no) [yes]:
>
The newer Argon2i password hasher requires PHP 7.2, libsodium or paragonie/sodium_compat. Your system DOES support this algorithm.
You should use Argon2i unless your production system will not support it.
Use Argon2i as your password hasher (bcrypt will be used otherwise) ? (yes/no) [yes]:
>
created: src/Entity/Users.php
created: src/Repository/UsersRepository.php
updated: src/Entity/Users.php
updated: config/packages/security.yaml
Success !
Next Steps:
- Review your new App E ntity U sers class.
- Use make:entity to add more fields to your Users entity and then run make:migration.
- Create a way to authenticate ! See https://symfony.com/doc/current/security.html # api/src/Entity/Users.php
/**
* @see UserInterface
*/ # api/src/Entity/Users.php
/**
* @ORMEntity(repositoryClass="AppRepositoryUsersRepository")
*/
class Users implements UserInterface
{
...
}您可以在此存储库中清楚地看到一些预先实现的功能,例如FindbyId(),但现在让我们创建另一个功能,可以帮助我们创建新用户。
# api/src/Repository/UsersRepository.php
class UsersRepository extends ServiceEntityRepository
{
/** EntityManager $manager */
private $ manager ;
. . . .
}并在构造函数中初始化以下内容:
# api/src/Repository/UsersRepository.php
/**
* UsersRepository constructor.
* @param RegistryInterface $registry
*/
public function __construct ( RegistryInterface $ registry )
{
parent :: __construct ( $ registry , Users::class);
$ this -> manager = $ registry -> getEntityManager ();
} # api/src/Repository/UsersRepository.php
/**
* Create a new user
* @param $data
* @return Users
* @throws DoctrineORMORMException
* @throws DoctrineORMOptimisticLockException
*/
public function createNewUser ( $ data )
{
$ user = new Users ();
$ user -> setEmail ( $ data [ ' email ' ])
-> setPassword ( $ data [ ' password ' ]);
$ this -> manager -> persist ( $ user );
$ this -> manager -> flush ();
return $ user ;
}$ docker-compose exec php bin/console make:controller
Choose a name for your controller class (e.g. TinyJellybeanController):
> AuthController
created: src/Controller/AuthController.php
created: templates/auth/index.html.twig
Success !
Next: Open your new controller class and add some pages ! # api/src/Controller/AuthController.php
use App Repository UsersRepository ;
class AuthController extends AbstractController
{
/** @var UsersRepository $userRepository */
private $ usersRepository ;
/**
* AuthController Constructor
*
* @param UsersRepository $usersRepository
*/
public function __construct ( UsersRepository $ usersRepository )
{
$ this -> usersRepository = $ usersRepository ;
}
. . . . . . .
} # api/config/services.yaml
services :
......
# Repositories
app.user.repository :
class : AppRepositoryUsersRepository
arguments :
- SymfonyBridgeDoctrineRegistryInterface
# Controllers
app.auth.controller :
class : AppControllerAuthController
arguments :
- ' @app.user.repository ' # api/src/Controller/AuthController.php
# Import those
use Symfony Component HttpFoundation Request ;
use Symfony Component HttpFoundation Response ;
# Then add this to the class
/**
* Register new user
* @param Request $request
*
* @return Response
*/
public function register ( Request $ request )
{
$ newUserData [ ' email ' ] = $ request -> get ( ' email ' );
$ newUserData [ ' password ' ] = $ request -> get ( ' password ' );
$ user = $ this -> usersRepository -> createNewUser ( $ newUserData );
return new Response ( sprintf ( ' User %s successfully created ' , $ user -> getUsername ()));
} # src/config/routes.yaml
# Register api
register :
path : /register
controller : AppControllerAuthController::register
methods : ['POST']$ docker-compose exec php bin/console make:migration
$ docker-compose exec php bin/console doctrine:migrations:migrate
WARNING ! You are about to execute a database migration that could result in schema changes and data loss. Are you sure you wish to continue ? (y/n) y$ curl -X POST -H " Content-Type: application/json " " http://localhost:8080/[email protected]&password=test1 "
User [email protected] successfully created$ docker-compose exec db psql -U api-platform api
psql (10.8)
Type " help " for help.
$ api= # select * from users;
id | email | roles | password
----+----------------+-------+----------
6 | [email protected] | [] | test1
(1 row) # api/src/Repository/UsersRepository.php
use Symfony Component Security Core Encoder UserPasswordEncoderInterface ;
class UsersRepository extends ServiceEntityRepository
{
.......
/** UserPasswordEncoderInterface $encoder */
private $ encoder ;
/**
* UserRepository constructor.
* @param RegistryInterface $registry
* @param UserPasswordEncoderInterface $encoder
*/
public function __construct ( RegistryInterface $ registry , UserPasswordEncoderInterface $ encoder )
{
parent :: __construct ( $ registry , Users::class);
$ this -> manager = $ registry -> getEntityManager ();
$ this -> encoder = $ encoder ;
}
} # api/config/services.yaml
services :
.......
# Repositories
app.user.repository :
class : AppRepositoryUsersRepository
arguments :
- SymfonyBridgeDoctrineRegistryInterface
- SymfonyComponentSecurityCoreEncoderUserPasswordEncoderInterface # api/src/Repository/UsersRepository.php
public function createNewUser ( $ data )
{
$ user = new Users ();
$ user -> setEmail ( $ data [ ' email ' ])
-> setPassword ( $ this -> encoder -> encodePassword ( $ user , $ data [ ' password ' ]));
. . . . . . .
}$ curl -X POST -H " Content-Type: application/json " " http://localhost:8080/[email protected]&password=test2 "
User [email protected] successfully created$ api= # select * from users;
id | email | roles | password
----+----------------+-------+-------------------------------------------------------------------------------------------------
6 | [email protected] | [] | test1
7 | [email protected] | [] | $argon2i$v =19 $m =1024,t=2,p=2 $VW9tYXEzZHp5U0RMSE5ydA$bo +V1X6rgYZ4ebN/bs1cpz+sf+DQdx3Duu3hvFUII8M
(2 rows)$ docker-compose exec php composer require jwt-auth$ curl -X GET -H " Content-Type: application/json " " http://localhost:8080/greetings "
{
" @context " : " /contexts/Greeting " ,
" @id " : " /greetings " ,
" @type " : " hydra:Collection " ,
" hydra:member " : [],
" hydra:totalItems " : 0
} # api/src/Controller/AuthController.php
/**
* api route redirects
* @return Response
*/
public function api ()
{
return new Response ( sprintf ( " Logged in as %s " , $ this -> getUser ()-> getUsername ()));
} # api/config/routes.yaml
api :
path : /api
controller : AppControllerAuthController::api
methods : ['POST']现在,我们需要在我们的安全配置文件中进行一些配置:
# api/config/packages/security.yaml
app_user_provider :
entity :
class : AppEntityUsers
property : email # api/config/packages/security
register :
pattern : ^/register
stateless : true
anonymous : true # api/config/packages/security.yaml
main :
anonymous : false
stateless : true
provider : app_user_provider
json_login :
check_path : /login
username_path : email
password_path : password
success_handler : lexik_jwt_authentication.handler.authentication_success
failure_handler : lexik_jwt_authentication.handler.authentication_failure
guard :
authenticators :
- lexik_jwt_authentication.jwt_token_authenticator # api/config/packages/security.yaml
api :
pattern : ^/api
stateless : true
anonymous : false
provider : app_user_provider
guard :
authenticators :
- lexik_jwt_authentication.jwt_token_authenticator正如您在上面的配置中看到的那样,我们将匿名设置为false ,我们不希望任何人现在访问这两个API,也告诉您为您服务的框架是我们以前定义的用户提供商,最后我们告诉它您将使用哪个身份验证器和身份验证Success/Faliure Messages。
现在,如果您尝试了电话,我们在 /问候API的附加部分中尝试了它
$ curl -X GET -H " Content-Type: application/json " " http://localhost:8080/greetings "
{
" code " : 401,
" message " : " JWT Token not found "
}$ curl -X POST -H " Content-Type: application/json " " http://localhost:8080/api "
{
" code " : 401,
" message " : " JWT Token not found "
} # api/config/packages/security.yaml
... .
json_login :
check_path : /login
# api/config/routes.yaml
# Login check to log the user and generate JWT token
api_login_check :
path : /login
methods : ['POST']$ curl -X POST -H " Content-Type: application/json " http://localhost:8080/login -d ' {"email":"[email protected]","password":"test2"} '
{ " token " : " eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpYXQiOjE1NTg2OTg4MTIsImV4cCI6MTU1ODcwMjQxMiwicm9sZXMiOlsiUk9MRV9VU0VSIl0sInVzZXJuYW1lIjoidGVzdDJAbWFpbC5jb20ifQ.nzd5FVhcyrfjYyN8jRgYFp3VOB2QytnPPRGNyp4ZtfLx6IRwg0TWZJPu5OFtOKPkdLO8DQAr_4Fpq_G6oPjzoxmGOASNuRoQonik9FCCq6oAIW3k5utzQecXDVE_ImnfgByc6WYW6a-aWLnsq1qtvxy274ojqdR0rWLePwSWX5K5-t08zDBgavO_87dVpYd0DLwhHIS7F10lNscET7bfWS-ioPDTv-G74OvkcpbcjgwHhXlO7TYubnrES-FsvAw7kezQe4BPxdbXr1w-XBZuqTNEU4MyrBuadSLgjoe_gievNBtkVhKErIkEQZVjeJIQ4xaKaxwmPxZcP9jYkE47myRdbMsL9XHSd0XmGq0bPuGjOJ2KLTmUb5oeuRnY-e9Q_V9BbouEGw0sjw2meo6Jot2MZyv5ZnLci_GwpRtWqmV7ZLw5jNyiLDFXR1rz70NcJh7EXqu9o4nno3oc68zokfDQvGkJJJZMtBrLCK5pKGMh0a1elIz41LRLZvpLYCrOZ2f4wCkGRD_U92iILD6w8EdVWGoO1wTn5Z2k8-GS1-QH9f-4KkOpaYGPCwwdrY7yioSt2oVbEj2FOb1jULteeP_Cpu44HyJktPLPW_wrN2OtZlUFr4Vz_owDSIvNESYk1JBQ_Fjlv9QGmUs9itzaDExjfB4QYoGkvpfNymtw2PI " }如您所见,它为我创建了JWT令牌,因此我可以使用它来调用应用程序中的任何API。如果显示出一些例外,例如无法为指定的配置生成令牌,请在此处检查此步骤。首先打开您.env文件,我们需要JWT_Passphrase ,因此请保持打开状态
$ mkdir -p api/config/jwt
$ openssl genrsa -out api/config/jwt/private.pem -aes256 4096 # this will ask you for the JWT_PASSPHRASE
$ openssl rsa -pubout -in api/config/jwt/private.pem -out api/config/jwt/public.pem # will confirm the JWT_PASSPHRASE again$ curl -X GET -H " Content-Type: application/json " -H " Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpYXQiOjE1NTg2OTg4MTIsImV4cCI6MTU1ODcwMjQxMiwicm9sZXMiOlsiUk9MRV9VU0VSIl0sInVzZXJuYW1lIjoidGVzdDJAbWFpbC5jb20ifQ.nzd5FVhcyrfjYyN8jRgYFp3VOB2QytnPPRGNyp4ZtfLx6IRwg0TWZJPu5OFtOKPkdLO8DQAr_4Fpq_G6oPjzoxmGOASNuRoQonik9FCCq6oAIW3k5utzQecXDVE_ImnfgByc6WYW6a-aWLnsq1qtvxy274ojqdR0rWLePwSWX5K5-t08zDBgavO_87dVpYd0DLwhHIS7F10lNscET7bfWS-ioPDTv-G74OvkcpbcjgwHhXlO7TYubnrES-FsvAw7kezQe4BPxdbXr1w-XBZuqTNEU4MyrBuadSLgjoe_gievNBtkVhKErIkEQZVjeJIQ4xaKaxwmPxZcP9jYkE47myRdbMsL9XHSd0XmGq0bPuGjOJ2KLTmUb5oeuRnY-e9Q_V9BbouEGw0sjw2meo6Jot2MZyv5ZnLci_GwpRtWqmV7ZLw5jNyiLDFXR1rz70NcJh7EXqu9o4nno3oc68zokfDQvGkJJJZMtBrLCK5pKGMh0a1elIz41LRLZvpLYCrOZ2f4wCkGRD_U92iILD6w8EdVWGoO1wTn5Z2k8-GS1-QH9f-4KkOpaYGPCwwdrY7yioSt2oVbEj2FOb1jULteeP_Cpu44HyJktPLPW_wrN2OtZlUFr4Vz_owDSIvNESYk1JBQ_Fjlv9QGmUs9itzaDExjfB4QYoGkvpfNymtw2PI " " http://localhost:8080/greetings "
{
" @context " : " /contexts/Greeting " ,
" @id " : " /greetings " ,
" @type " : " hydra:Collection " ,
" hydra:member " : [],
" hydra:totalItems " : 0
}
$ curl -X GET -H " Content-Type: application/json " " http://localhost:8080/greetings "
{
" code " : 401,
" message " : " JWT Token not found "
}我想现在您看到了差异。
$ curl -X POST -H " Content-Type: application/json " -H " Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpYXQiOjE1NTg2OTg4MTIsImV4cCI6MTU1ODcwMjQxMiwicm9sZXMiOlsiUk9MRV9VU0VSIl0sInVzZXJuYW1lIjoidGVzdDJAbWFpbC5jb20ifQ.nzd5FVhcyrfjYyN8jRgYFp3VOB2QytnPPRGNyp4ZtfLx6IRwg0TWZJPu5OFtOKPkdLO8DQAr_4Fpq_G6oPjzoxmGOASNuRoQonik9FCCq6oAIW3k5utzQecXDVE_ImnfgByc6WYW6a-aWLnsq1qtvxy274ojqdR0rWLePwSWX5K5-t08zDBgavO_87dVpYd0DLwhHIS7F10lNscET7bfWS-ioPDTv-G74OvkcpbcjgwHhXlO7TYubnrES-FsvAw7kezQe4BPxdbXr1w-XBZuqTNEU4MyrBuadSLgjoe_gievNBtkVhKErIkEQZVjeJIQ4xaKaxwmPxZcP9jYkE47myRdbMsL9XHSd0XmGq0bPuGjOJ2KLTmUb5oeuRnY-e9Q_V9BbouEGw0sjw2meo6Jot2MZyv5ZnLci_GwpRtWqmV7ZLw5jNyiLDFXR1rz70NcJh7EXqu9o4nno3oc68zokfDQvGkJJJZMtBrLCK5pKGMh0a1elIz41LRLZvpLYCrOZ2f4wCkGRD_U92iILD6w8EdVWGoO1wTn5Z2k8-GS1-QH9f-4KkOpaYGPCwwdrY7yioSt2oVbEj2FOb1jULteeP_Cpu44HyJktPLPW_wrN2OtZlUFr4Vz_owDSIvNESYk1JBQ_Fjlv9QGmUs9itzaDExjfB4QYoGkvpfNymtw2PI " " http://localhost:8080/api "
Logged in as [email protected]正如您只能从JWT令牌中看到的那样,您才能知道确切的登录谁,并且可以通过隐含添加剂用户属性(例如Isactive或Userroles ...等)来改进它。