Is anyone out there?
I am using Laravel 5 and I have a custom User/Auth implementation.
I (think I) successfully built:
and I set up my jwt config (hopefully) appropriately:
'user' => 'App\WLAuth\WLUser',
...
'providers' => [
'user' => 'App\WLAuth\WLUserProvider',
'auth' => function ($app) {
// return new Tymon\JWTAuth\Providers\Auth\IlluminateAuthAdapter($app['auth']);
return new App\WLAuth\WLAuthProvider($app['auth']);
},
Now, I've been trying for a quite a bit to get my user stuff running with JWT and inspected the source here and there, but I cannot make it work :/
So, as soon as I use the JWTAuth Facade (in this case using attempt), I am presented with this:
Unresolvable dependency resolving [Parameter #0 [ <required> $row ]] in class App\WLAuth\WLUser
Which is due to the constructor of my User model. (I instantiate the user based on the $row variable, feeding it some data).
I thought the usage of the UserProvider would circumvent that, but fine, let's roll with it. So I instantiate the user by myself, and try using fromUser which of course also instantiates the Facade and complaining about my proudly self constructed user model.
After digging a bit more and modifying some code, I found, that the JWTAuth facade requires me to hand over something, that implements the Tymon\Providers\User\UserInterface:
Argument 2 passed to Tymon\JWTAuth\JWTAuth::__construct() must be an instance of Tymon\JWTAuth\Providers\User\UserInterface, instance of App\WLAuth\WLUserProvider given, called in /Users/ybaron/Projects/laravel/vendor/tymon/jwt-auth/src/Providers/JWTAuthServiceProvider.php
Any ideas here?
_I'm starting to believe, that the comments in the config are misleading and I have to implement all of these interfaces myself again although my Auth already implements all of the related Laravel interfaces._
EDIT No1:
After implementing some interfaces, changing my classes and doing more tracking work, I found that in tymon/jwt-auth/src/Providers/JWTAuthServiceProvider.php a User is instantiated.
/**
* Register the bindings for the User provider
*/
protected function registerUserProvider()
{
$this->app['tymon.jwt.provider.user'] = $this->app->share(function ($app) {
return $app->make($this->config('providers.user'), [$app->make($this->config('user'))]);
});
}
I assume that there is a reason (to make the magic work) why a User object is instantiated here.
Also, I had to check the reference implementation, as the comments in the code are not very helpful:
/**
* Check a user's credentials
*
* @param array $credentials
* @return bool
*/
public function byCredentials(array $credentials = []);
So I assumed, I return a boolean based on correct credentials. In fact, I have to log in the user here, otherwise the user() method does not have anything to return.
_Please someone stop me from digging deeper, I must be doing something wrong because I am basically reimplementing stuff that I feel should have been taken care off already._
EDIT No2:
I changed the jwt config back to use the default Auth provider and made my UserProvider implement UserInterface.
'user' => 'App\WLAuth\WLUser',
...
'providers' => [
'user' => 'App\WLAuth\WLUserProvider',
Conclusion so far, using a custom user model:
Tymon\JWTAuth\Providers\User\UserInterfaceOkay after a bit more struggling, I will now sum up all the steps to make this work with a custom implementation for user/auth in Laravel 5.
_Maybe some day, someone out there might need this as much as I needed it. Afterwards you're always a bit smarter, huh_
Step 1
Install the package and create the configuration, pretty much like on the Github page.
Step 2
Set up the config to match your custom UserModel and custom UserProvider:
// property of your user model to identify users, used as 'sub' claim in the token
'identifier' => 'uid',
[...]
// your usermodel
'user' => 'App\WLAuth\WLUser',
[...]
// your userprovider
'providers' => [
'user' => 'App\WLAuth\WLUserProvider',
[...]
]
Step 3
Make sure your UserModel can be instantiated with an empty constructor.
_Don't worry, it will be instantiated by your UserProvider in the end. Just for some part of the implementation, it needs to be instantiated without parameters._
So this will work:
public function __construct($userdata = null, $moredata = null) {
if (!$userdata) return;
[...]
}
Step 4
Make sure the identifier property defined in _Step 1_ is public in your UserModel.
class WLUser implements Authenticatable {
public $uid;
[...]
}
Step 5
Make your UserProvider implements the Tymon\JWTAuth\Providers\User\UserInterface.
Essentially, this means you need to implement a method getBy($key, $value) that returns a user object fetched by the identifier property. $key will be the name of the identifier property and $value its value. In my example I make use of the UserProvider's userById() method.
public function getBy($key, $value) {
return $this->userById($value);
}
Step 6
Use the package as intended.
_In case you were too lazy reading the Authentication section of the great wiki, I want to point you there to make you aware of the issues with Apache losing the token in the Authorization header. Didn't happen to me, but maybe you skipped on some reading :)_
@npx Would it be possible to create a gist with the files you had to create for this to work?
Thank you (so very much) in advance, and I do apologise if I'm asking too much! :)
@geoah which files do you mean? The one of my custom auth?
As for using this package I did not create any files except for the config maybe, which can be created with the respective artisan command.
@npx I implemented your steps, but still middleware is not using this provider.
Thank you so much you made my day.
@npx I followed your instructions and it worked. Thanks!
EDIT: This error persists in middlewares: jwt.auth jwt.refresh. Any ideas of how it can be solved?
@vivex
If you are using a custom User model like me, you'll have to set jwt.providers.auth too, injwt.php config file, in order to user the middlewares defined in the package.
Also make sure to change the user model in users provider in auth.php and make your custom User model implement Illuminate\Contracts\Auth\Authenticatable interface.
That should make the middlewares work.
_I propose changing the docs to add this useful piece of information for people using custom User models._
Most helpful comment
Okay after a bit more struggling, I will now sum up all the steps to make this work with a custom implementation for user/auth in Laravel 5.
_Maybe some day, someone out there might need this as much as I needed it. Afterwards you're always a bit smarter, huh_
Step 1
Install the package and create the configuration, pretty much like on the Github page.
Step 2
Set up the config to match your custom UserModel and custom UserProvider:
Step 3
Make sure your UserModel can be instantiated with an empty constructor.
_Don't worry, it will be instantiated by your UserProvider in the end. Just for some part of the implementation, it needs to be instantiated without parameters._
So this will work:
Step 4
Make sure the identifier property defined in _Step 1_ is public in your UserModel.
Step 5
Make your UserProvider implements the
Tymon\JWTAuth\Providers\User\UserInterface.Essentially, this means you need to implement a method
getBy($key, $value)that returns a user object fetched by the identifier property.$keywill be the name of the identifier property and$valueits value. In my example I make use of the UserProvider'suserById()method.Step 6
Use the package as intended.
_In case you were too lazy reading the Authentication section of the great wiki, I want to point you there to make you aware of the issues with Apache losing the token in the Authorization header. Didn't happen to me, but maybe you skipped on some reading :)_