Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lexik user_identity_field can't be the id (integer) #984

Closed
mowabidev opened this issue Feb 2, 2022 · 6 comments
Closed

Lexik user_identity_field can't be the id (integer) #984

mowabidev opened this issue Feb 2, 2022 · 6 comments

Comments

@mowabidev
Copy link

mowabidev commented Feb 2, 2022

I'm trying to implement JWT authentication with Symfony 6.0. I'm using Lexik and I want to use the database-less configuration. For that my user extends JWTUserInterface, PasswordAuthenticatedUserInterface and I added the createFromPayload method as below.

# App\Entity\User.php

class User implements JWTUserInterface, PasswordAuthenticatedUserInterface
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column(type: 'integer')]
    #[Groups(['read:users', 'read:type', 'read:payments'])]
    private $id;

    #[ORM\Column(type: 'json')]
    #[Groups(['read:user'])]
    private $roles = [];

    #[ORM\Column(type: 'string')]
    private $password;

    #[ORM\Column(type: 'string', length: 255, unique: true)]
    #[
      Groups(['read:user']),
      Length(exactly: 8, groups: ["create:user"])
    ]
    private $phone;

    public function __construct()
    {}

    public function getId(): ?int
    {
        return $this->id;
    }

    public function setId(int $id): self
    {
        $this->id = $id;

        return $this;
    }

    /**
     * @see UserInterface
     */
    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): self
    {
        $this->roles = $roles;

        return $this;
    }

    /**
     * @see PasswordAuthenticatedUserInterface
     */
    public function getPassword(): string
    {
        return $this->password;
    }

    public function setPassword(string $password): self
    {
        $this->password = $password;

        return $this;
    }

    /**
     * Returning a salt is only needed, if you are not using a modern
     * hashing algorithm (e.g. bcrypt or sodium) in your security.yaml.
     *
     * @see UserInterface
     */
    public function getSalt(): ?string
    {
        return null;
    }

    /**
     *
     * @see UserInterface
     */
    public function getUsername(): ?string
    {
        return $this->phone;
    }

    /**
     * @see UserInterface
     */
    public function eraseCredentials()
    {
        // If you store any temporary, sensitive data on the user, clear it here
        // $this->plainPassword = null;
    }

    public function getUserIdentifier(): string
    {
        // If you store any temporary, sensitive data on the user, clear it here
        // $this->plainPassword = null;
        return $this->phone;
    }

    public function getPhone(): ?string
    {
        return $this->phone;
    }

    public function setPhone(string $phone): self
    {
        $this->phone = $phone;

        return $this;
    }
    
    public static function createFromPayload($id, array $payload)
    {
      $user = new User();
      //    ->setPhone($payload["username"]);
      //dd($id);

      return $user;
    }
}

Then, as mentioned in the Lexik documentation here I set user_identity_field to id.

# config/packages/lexik_jwt_authentication.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 # in seconds, default is 3600
  user_identity_field: id

To authenticate the user, I use the phone as UserIdentifier. The authentication works fine. But when I then try to retrieve the usage data, I get the following error.

Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge::__construct(): Argument #1 ($userIdentifier) must be of type string, int given, called in /home/.../vendor/lexik/jwt-authentication-bundle/Security/Authenticator/JWTAuthenticator.php on line 121

When I remove user_identifier from the Lexik configuration, I get the following error

Unable to generate an IRI for "App\Entity\User"

I followed the Lexik documentation, so I think the problem must be with Symfony's Badge authentication system.

Does anyone have an idea on how I can solve the problem?

Thank you.

@fd6130
Copy link

fd6130 commented Feb 3, 2022

Already fixed in #976 , waiting @chalasr to make a new release.

And this is another way to hack it:

save as integer in database but return with string cast.

    public function getId(): ?string
    {
        return (string) $this->id;
    }

@mowabidev
Copy link
Author

thanks @fd6130 . I tried your solution, but it doesn't work anyway. I will see how I can exploit the fix of issue #976

@chalasr
Copy link
Collaborator

chalasr commented Feb 3, 2022

@worksfather If you can try using 2.x@dev and confirm it fixes the issue, that would be awesome.

@DaedalusDev
Copy link

@chalasr it fixes the issue (Thank you @Floruzus 🎉).

Did you plan to release a new version including this fix soon ?

@FrenchGithubUser
Copy link

FrenchGithubUser commented Apr 19, 2022

having the same issue here, any news ? Will it be supported in an upcoming release ?

@chalasr
Copy link
Collaborator

chalasr commented Apr 19, 2022

The fix has been released in https://github.com/lexik/LexikJWTAuthenticationBundle/releases/tag/v2.15.0 and v2.15.1 has been tagged meanwhile. Please open a new issue if you think you found a bug. Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants