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

Update last_used_at in terminable middleware #141

Closed
AlinIonut opened this issue May 12, 2020 · 5 comments
Closed

Update last_used_at in terminable middleware #141

AlinIonut opened this issue May 12, 2020 · 5 comments

Comments

@AlinIonut
Copy link

I'm working on an application where we have a MySql database cluster that's running in replica, one Reader and one Write. Our API is optimized as much as possible to handle high traffic, and (at least for GET endpoints) we strive to only "Read" data from database (where possible - moving and write in terminable middleware), but after switching to sanctum authorization mechanism, this principle (GET only Read data from reader replica) is not applied anymore, hitting also the Writer replica, before API send back the response.

I'm wondering if we can move the sanctum last_used_at property update on a terminable middleware, to avoid this matter.

Thanks.

@lao9s
Copy link

lao9s commented May 17, 2020

Hi,
You can override the file from package wich write data in last_used_at column.

in your composer.json put this code inside autoload object

"exclude-from-classmap": ["vendor/laravel/sanctum/src/Guard.php"],
"psr-4": {
  "App\\": "app/",
  "Laravel\\Sanctum\\": "app/overrides/sanctum"
}

After that, you need to create new folders app/overrides/sanctum and copy here the file Guard.php from vendor/laravel/sanctum/src/Guard.php.

In the copied file, need to change the last return from method _invoke

return $this->supportsTokens($accessToken->tokenable) ? $accessToken->tokenable->withAccessToken(
	$accessToken
	/*
	* Disable
	*/
	// tap($accessToken->forceFill(['last_used_at' => now()]))->save()
) : null;

And finally, run composer dump-autoload. That is all.

Be carefully in the future when you update this package, you need to check if original file of your custom file don't have a changes.

@AlinIonut AlinIonut reopened this May 19, 2020
@AlinIonut
Copy link
Author

Hi,
You can override the file from package wich write data in last_used_at column.

in your composer.json put this code inside autoload object

"exclude-from-classmap": ["vendor/laravel/sanctum/src/Guard.php"],
"psr-4": {
  "App\\": "app/",
  "Laravel\\Sanctum\\": "app/overrides/sanctum"
}

After that, you need to create new folders app/overrides/sanctum and copy here the file Guard.php from vendor/laravel/sanctum/src/Guard.php.

In the copied file, need to change the last return from method _invoke

return $this->supportsTokens($accessToken->tokenable) ? $accessToken->tokenable->withAccessToken(
	$accessToken
	/*
	* Disable
	*/
	// tap($accessToken->forceFill(['last_used_at' => now()]))->save()
) : null;

And finally, run composer dump-autoload. That is all.

Be carefully in the future when you update this package, you need to check if original file of your custom file don't have a changes.

Thanks, but this is not an option for me :)

@driesvints
Copy link
Member

You can overwrite the PersonalAccessToken model by using Sanctum::usePersonalAccessTokenModel(string $model) to customize the PersonalAccessToken model and set the connection.

@MarekGogol
Copy link

MarekGogol commented May 22, 2022

@AlinIonut

  1. replace token model docs
  2. add setter
use Laravel\Sanctum\PersonalAccessToken as SanctumPersonalAccessToken;

class PersonalAccessToken extends SanctumPersonalAccessToken
{
    public function setLastUsedAtAttribute($value)
    {
        //...
    }
}

done

@alexdemers
Copy link

A complete solution to this

  1. Create a middleware php artisan make:middleware UpdatePersonalAccessToken
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;

class UpdatePersonalAccessToken
{
    public function handle(Request $request, Closure $next)
    {
        $response = $next($request);

        $request->user()?->currentAccessToken()?->setRawAttributes(['last_used_at' => now()])->save();

        return $response;
    }
}
  1. Add your middleware to the api middleware group in app/Http/Kernel.php
  2. Set your middleware to the bottom of the $middlewarePriority property
<?php

class Kernel extends HttpKernel
{
    ...

    protected $middlewarePriority = [
        ...other middlewares,
        UpdatePersonalAccessToken::class
    ];
}
  1. Extend Sanctum's PersonalAccessToken model to use your custom one:
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Casts\Attribute;
use Laravel\Sanctum\PersonalAccessToken as SanctumPersonalAccessToken;

class PersonalAccessToken extends SanctumPersonalAccessToken
{
    protected function lastUsedAt(): Attribute
    {
        // We need to set it to the same value as the original so the `UPDATE` won't execute
        return Attribute::make(
            set: fn () => $this->getOriginal('last_used_at')
        );
    }
}
  1. In your AppServiceProvider, tell Sanctum to use your new custom PersonalAccessToken model.
<?php

namespace App\Providers;

use App\Models\PersonalAccessToken;
use Illuminate\Support\ServiceProvider;
use Laravel\Sanctum\Sanctum;

class AppServiceProvider extends ServiceProvider
{
    public function boot()
    {
        Sanctum::usePersonalAccessTokenModel(PersonalAccessToken::class);
    }
}

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