简体   繁体   中英

LexikJWTAuthenticationBundle with multiple providers

I 2 part of applications - first for admins (admin panel) and second API. For API I want to use another model to check credentials and that retrieve a token. I thought that it could be achieved by specified check_path route where I can verify the provided data and then return manually token.

But It seems that the application doesn't event go to this endpoint because I haven`t seen any debug message from the response - only 401 error code. Here is my security.yml config:

security:
    encoders:
        App\Entity\Security\AdminUser:
            algorithm: bcrypt
        Lexik\Bundle\JWTAuthenticationBundle\Security\User\JWTUser:
            algorithm: bcrypt

role_hierarchy:
    ROLE_ADMIN:       ROLE_USER
    ROLE_SUPER_ADMIN: ROLE_ADMIN
providers:
    fos_userbundle:
        id: fos_user.user_provider.username_email
    jwt:
        lexik_jwt: ~

firewalls:
    api:
        provider: jwt
        pattern:  ^/api/
        stateless: true
        anonymous: true
        guard:
            authenticators:
                - 'jwt.token.authenticator'
        json_login:
            check_path: api.v1.0.token.get
            username_path: passwordName
            success_handler: lexik_jwt_authentication.handler.authentication_success
            failure_handler: lexik_jwt_authentication.handler.authentication_failure
    dev:
        pattern: ^/(_(profiler|wdt)|css|images|js)/
        security: false
    main:
        context: 'main'
        pattern: ^/
        form_login:
            provider: fos_userbundle
            default_target_path: easyadmin
            csrf_token_generator: security.csrf.token_manager

        logout:       true
        anonymous:    true


access_control:
    - { path: ^/api/doc, roles: IS_AUTHENTICATED_ANONYMOUSLY }
    - { path: ^/api/v1.0/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
    - { path: ^/api,       roles: IS_AUTHENTICATED_FULLY }

And here is my action where I tried to debug:

class TokenController extends AbstractController
{
/**
 * @Route("/login", name="api.v1.0.token.get", methods={"POST"})
 * @param Request $request
 */
public function obtainToken(Request $request, JWTEncoderInterface $encoder, SiteRepository $siteRepository)
  {
      dd(123); // I don`t see this message - only 401 error

  }
}

First, I'm not sure what you're trying to do with your obtainToken function but if you need to either create a token programatically or manipulate / customize its content before returning it, I highly suggest that you have a look at their documentation first as you'll have all the tools to achieve what you want to do:

Otherwise, the bundle will handle that for you.

Now, assuming that you simply want to protect your api with JWT, you'll need to separate your api firewall into two different ones:

First one to login, like so:

login:
  pattern: ^/api/login
  stateless: true
  anonymous: true
  json_login:
    check_path: /api/login_check
    success_handler: lexik_jwt_authentication.handler.authentication_success
    failure_handler: lexik_jwt_authentication.handler.authentication_failure

And don't forget to update the access control to make sure your users can access it anonymously:

- { path: ^/api/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }

This will allow you to hit /api/login_check with the credentials to authenticate and obtain your token.


Then, protect the rest of your public api by defining the JWT guard authenticator, like so:

api:
  pattern: ^/api
  stateless: true
  # /!\ shouldn't be anonymous: true here
  provider: jwt
  guard:
    authenticators:
    - lexik_jwt_authentication.jwt_token_authenticator

And the access control too:

- { path: ^/api, roles: IS_AUTHENTICATED_FULLY }

If you need to create an account, you can define your own route and create the token programmatically upon success.


Some other things to mention:

  • check_path: api.v1.0.token.get : I actually never tried but I don't think you can define a path by its route name like so, you better specify the path directly.
  • username_path: passwordName : here you're telling the bundle to use 'passwordName' as the username, which sounds weird.

If you want to specify custom identifiers for both username and password, you better use something like this:

username_path: email # (or whatever field you use for the authentication)
password_path: password

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM