-
Notifications
You must be signed in to change notification settings - Fork 787
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
[10.x] Make tokenRepository replaceable #1288
Conversation
@@ -95,7 +97,7 @@ public function revokeAccessToken($id) | |||
* @param string $id | |||
* @return bool | |||
*/ | |||
public function isAccessTokenRevoked($id) | |||
public function isAccessTokenRevoked($id): bool |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remove all of these return types that were added.
* @return \Laravel\Passport\Contracts\TokenRepository|void | ||
*/ | ||
public static function useTokenRepository( | ||
Contracts\TokenRepository $tokenRepository = null |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Import the full namespace and alias it as TokenRepositoryInterface
.
) { | ||
if (is_null($tokenRepository)) { | ||
return static::$tokenRepository = new TokenRepository(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would only allow this method to set a token repository and then register the base one in the service provider.
@@ -91,6 +91,7 @@ public function register() | |||
$this->mergeConfigFrom(__DIR__.'/../config/passport.php', 'passport'); | |||
|
|||
Passport::setClientUuids($this->app->make(Config::class)->get('passport.client_uuids', false)); | |||
Passport::useTokenRepository(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Register the token repository instead of using a static method. Place the registration in a separate method like the methods below.
* @param string $id | ||
* @return bool | ||
*/ | ||
public function isAccessTokenRevoked($id): bool; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove all of the return types on these methods.
You're saying this will solve #382 but I don't see how? Can you explain further? Also: why do you want to use a different database driver? |
Thanks for your pull request to Laravel! Unfortunately, I'm going to delay merging this code for now. To preserve our ability to adequately maintain the framework, we need to be very careful regarding the amount of code we include. If possible, please consider releasing your code as a package so that the community can still take advantage of your contributions! If you feel absolutely certain that this code corrects a bug in the framework, please "@" mention me in a follow-up comment with further explanation so that GitHub will send me a notification of your response. |
@driesvints Thanks for your recommends. And sorry for the unclear explanation. I want to write a demo token repository to explain why. It's just a demo and may have bugs, but it can help me explain how to solve #382. <?php
namespace App\Repositories;
use Illuminate\Database\Eloquent\Collection;
use Laravel\Passport\Contracts\TokenRepository;
use Laravel\Passport\Passport;
use Laravel\Passport\Token;
use Cache;
class CacheTokenRepository implements TokenRepository
{
protected $cache_key = 'passport_token_';
/**
* Creates a new Access Token.
*
* @param array $attributes
* @return \Laravel\Passport\Token
*/
public function create($attributes): Token
{
return Passport::token()->create($attributes);
}
/**
* Get a token by the given ID.
*
* @param string $id
* @return \Laravel\Passport\Token
*/
public function find($id): Token
{
return Cache::remember($this->cache_key.$id, now()->addMinutes(30), function() use ($id) {
return Passport::token()->where('id', $id)->first();
});
}
/**
* Get a token by the given user ID and token ID.
*
* @param string $id
* @param int $userId
* @return \Laravel\Passport\Token|null
*/
public function findForUser($id, $userId)
{
return Cache::remember($this->cache_key.$id, now()->addMinutes(30), function() use ($id, $userId) {
return Passport::token()->where('id', $id)->where('user_id', $userId)->first();
});
}
/**
* Get the token instances for the given user ID.
*
* @param mixed $userId
* @return \Illuminate\Database\Eloquent\Collection
*/
public function forUser($userId): Collection
{
return Cache::remember($this->cache_key.$userId, now()->addMinutes(30), function() use ($userId) {
return Passport::token()->where('user_id', $userId)->get();
});
}
/**
* Get a valid token instance for the given user and client.
*
* @param \Illuminate\Database\Eloquent\Model $user
* @param \Laravel\Passport\Client $client
* @return \Laravel\Passport\Token|null
*/
public function getValidToken($user, $client)
{
return Cache::remember($this->cache_key.$user->getKey(), now()->addMinutes(30), function() use ($client, $user) {
return $client->tokens()
->whereUserId($user->getKey())
->where('revoked', 0)
->where('expires_at', '>', Carbon::now())
->first();
});
}
/**
* Store the given token instance.
*
* @param \Laravel\Passport\Token $token
* @return void
*/
public function save(Token $token): void
{
$token->save();
}
/**
* Revoke an access token.
*
* @param string $id
* @return mixed
*/
public function revokeAccessToken($id)
{
return Passport::token()->where('id', $id)->update(['revoked' => true]);
}
/**
* Check if the access token has been revoked.
*
* @param string $id
* @return bool
*/
public function isAccessTokenRevoked($id): bool
{
if ($token = $this->find($id))
{
return $token->revoked;
}
return true;
}
/**
* Find a valid token for the given user and client.
*
* @param \Illuminate\Database\Eloquent\Model $user
* @param \Laravel\Passport\Client $client
* @return \Laravel\Passport\Token|null
*/
public function findValidToken($user, $client)
{
return $client->tokens()
->whereUserId($user->getKey())
->where('revoked', 0)
->where('expires_at', '>', Carbon::now())
->latest('expires_at')
->first();
}
}
<?php
namespace App\Providers;
...
use App\Repositories\CacheTokenRepository;
use Laravel\Passport\Contracts\TokenRepository;
...
class AuthServiceProvider extends ServiceProvider
{
...
public function boot()
{
...
$this->app->singleton(TokenRepository::class, CacheTokenRepository::class);
}
} In my custom tokenRepository, tokens are still store in database. I add a layer of cache. Here's the result: Also, in my latest commit, I did the change as you requested. Thanks again. |
You can simply swap out the token repository in your service provider: $this->app->singleton(TokenRepository::class, function () {
return /* your custom token repository */;
}); |
I totally forgot this way. That's what I need. Thanks ! |
@rust17 |
@rust17 @driesvints @taylorotwell TokenRepository is a class . not an interface <?php
namespace App\Repositories\Passport;
use Illuminate\Support\Facades\Cache;
use Laravel\Passport\TokenRepository;
class CacheTokenRepository extends TokenRepository
{
protected string $cache_key = 'passport-token';
public function find($id)
{
return Cache::remember("$this->cache_key-id-$id", now()->addMinutes(30), function () use ($id) {
return parent::find($id);
});
}
public function findForUser($id, $userId)
{
return Cache::remember("$this->cache_key-id-$id-user-$userId", now()->addMinutes(30), function () use ($id, $userId) {
return parent::findForUser($id, $userId);
});
}
public function forUser($userId)
{
return Cache::remember("$this->cache_key-user-$userId", now()->addMinutes(30), function () use ($userId) {
return parent::forUser($userId);
});
}
} then we can bind this class in AuthServiceProvider or in another service provider $this->app->bind(TokenRepository::class, function () {
return new CacheTokenRepository();
}); |
@sepisoltani found a better solution. You can take a look at this repo. |
This pr make the TokenRepository can be replace by custom tokenRepository. By adding
Passport::useTokenRepository(new CustomTokenRepository)
atApp\Providers\AuthServiceProvider
, it can be easily use cache or other database driver to manage the tokens. And also make it possible to solve problems like #347 #382