Is there a package for laravel that ads a unique identifier to each request in order to use it also for logs?
For example: I would know that request-id as12121-1212s-121 had an error and I could look into logs for any errors.
That request-id would be seen in the UI and I could debug when getting a printscreen with the error from the client
You can use $request->fingerprint()
This prints a uniqueid from your request and you can track it
public function fingerprint()
{
if (! $route = $this->route()) {
throw new RuntimeException('Unable to generate fingerprint. Route unavailable.');
}
return sha1(implode('|', array_merge(
$route->methods(),
[$route->getDomain(), $route->uri(), $this->ip()]
)));
}
If you need a unique id per request you can assign a uuid to the request via global middleware.
For example:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
class RequestUniqueId
{
public function handle(Request $request, Closure $next)
{
$uuid = (string) Str::uuid();
$request->headers->set('X-Request-ID', $uuid);
return $next($request);
}
}
This package might help
Laravel Request Logger
Related
I am implementing a Rest API.
It turns out that when using Postman I send a GET request to a route which receives as a parameter account_id = 100
http://127.0.0.1:8000/api/balance?account_id=100
ID 100 exists but postman keeps returning 404 error with return "0".
I am using Laravel 8 and I think my problem is in the Handler. I show you the BalanceController controller and also the Handler class.
BalanceController:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Account;
class BalanceController extends Controller
{
public function show(Request $request)
{
$accountId = $request->input('account_Id');
$account = Account::findOrFail($accountId);
return $account->balance;
}
}
Handler.php class register Method
public function register()
{
$this->renderable(function (NotFoundHttpException $e, $request) {
return response()->json('0',404);
});
}
The idea is that when I make this request, I will return the balance of said ID with the response 200, I repeat the ID = 100 exists since I create it by POST request at another time with the logic in another controller.
api routes.php
<?php
use Illuminate\Support\Facades\Route;
Route::post('/reset', [App\Http\Controllers\ResetController::class, 'reset']);
Route::get('/balance', [App\Http\Controllers\BalanceController::class,'show']);
Route::post('/event', [App\Http\Controllers\EventController::class, 'store']);
I would suggest that you implement this in Laravel's way. In your api.php, change your route so that it accepts a parameter like below.
Notice that {account_id} is then replaced with the actual ID number when a program hits this API route.
Route::get('/balance/{account_id}', [App\Http\Controllers\BalanceController::class,'show']);
and then, in your show() function, Add a second parameter like below:
public function show(Request $request, $account_id)
{
$account = Account::findOrFail($account_id);
return $account->balance;
}
I am writing a controller in which I would like to get the refresh token id but I just cannot figure out how to do it in laravel.
There are no problems with decrypting the access token. I am using standard protocol and receive data using the public key of the passport.
i tried different ways.
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class RefreshTokenController extends Controller
{
public static $public_key;
public static function refresh_token(Request $request)
{
self::$public_key = file_get_contents(storage_path() . DIRECTORY_SEPARATOR . 'oauth-public.key');
$refresh_token = $request->get('refresh_token');
$data = base64_decode($refresh_token);
$public_key = openssl_get_publickey(self::$public_key);
openssl_public_decrypt($data, $decrypted, $public_key);
dd($decrypted);
}
}
I tried also standard decrypt();. But it gives an error too.
Example of incoming data.
def50200dc11ab81fdb16530806530f85fe41f7facc934447589b3a0daa202d56f5b4a8265db94b418e09280bcc8a05c88c3817612200d3c28de15c9adfd4a213f7cb136fca6f78099d686fce8d5ddf93f9bb29c1df081d7f7b75394875b5287a7ca5d9ca5eb513ea13a26195aeda41c897832467ec1b0348cdb3e5ed9476e5e7d8712b8628c18ee8ffb525de965faeb3f25b1a8eb4ee904a15341650fe6d3ed901600beda0f80c71b9b607f3e549ba8fbd9eda0e02fc7647ab8b4ea9161f7eb65833bfe46fb7f3e116a207282f947660ead392dc78ad2b9501331b4d28433a421a4193484e113baf8050d3878bd94b6ac860a1a766e79877f1af8d3ab5aee3779bf33c2a7e347552e51bb8b5448585435ef7b79d06853bcd775ce781b8d2e56289dbc8d4a10ec507aecde19bb496e90f88a687ee9bb33755046d50f860f7723d87bd4c079cd4d1242903bdb3ca447ce6ab03f2fd800182d0d8c5a3b7de5402ba2ecb4058d458cbee94da433635877e63120d6418e51eafdfd763191fceef399c16c088e27da9ffbf9
according to oauth_refresh_tokens table. All refresh token IDs are preserved. When calling the refresh token method, according to the refresh token, the corresponding access token matches in the database and is renewed.
I will be grateful for solutions.
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use Defuse\Crypto\Crypto;
use Exception;
use Illuminate\Http\Request;
class RefreshTokenController extends Controller
{
public static function refresh_token(Request $request)
{
$refresh_token = $request->get('refresh_token');
$app_key = env('APP_KEY');
$enc_key = base64_decode(substr($app_key, 7));
try {
$crypto = Crypto::decryptWithPassword($refresh_token, $enc_key);
} catch (Exception $exception){
return $exception;
}
return json_decode($crypto, true);
}
}
Laravel Passport encrypts the password using the APP_ located in the ENV file.
Using the library Defuse\Crypto\Crypto;
I'm attempting to rebind what $request->user() returns, and having poked through the built in authentication code, I found a service using app->rebinding to request->setUserResolver is how it's done? I tried it myself, with no luck. I created a service (well, coopted AuthServiceProvider, and changed the register to:
public function register()
{
$this->app->rebinding('request', function ($app, $request) {
$request->setUserResolver(function () use ($app) {
$token = $this->request->bearerToken();
dd($token);
// error_log($token);
return array('user' => 1);
});
});
}
Ignoring the dd, which is there to test, how can I find where I'm going wrong? I even found a SO answer that seems to indicate this is the way to go but nothing gets dumped, nothing gets logged (when error log isn't commented out) and dumping $request->user() in my controller just returns null.
I know I can use the built in auth/guard setup, but I figured since I'm not using most of what the auth/guard setup has, why not try to learn and set it up myself? Of course, so far I've gotten nowhere. I'm going to fall back to using the built-in stuff, but I'd like to learn and improve.
As I realized it may make a difference, I'm running Lumen 5.4.
In Lumen, your App\Providers\AuthServiceProvider class comes by default with
public function boot()
{
// Here you may define how you wish users to be authenticated for your Lumen
// application. The callback which receives the incoming request instance
// should return either a User instance or null. You're free to obtain
// the User instance via an API token or any other method necessary.
$this->app['auth']->viaRequest('api', function ($request) {
if ($request->input('api_token')) {
return User::where('api_token', $request->input('api_token'))->first();
}
});
}
This is the place to define the user resolution logic. The rebinding you were registering in the register method was being supeseded by this one.
Just uncomment the $app->register(App\Providers\AuthServiceProvider::class); line in bootstrap/app.php to register your provider; don't modify the code in the vendor folder (if I understood correctly you were doing that).
Update
I now see what you mean, although I'm not sure it is really too much "load" for the auth/guard method.
However, in the interest of creating a minimal implementation, I think the solution would be overriding the prepareRequest method of the Application class.
In bootstrap/app.php replace
$app = new Laravel\Lumen\Application(
realpath(__DIR__.'/../')
);
with
$app = new class (realpath(__DIR__.'/../')) extends Laravel\Lumen\Application {
protected function prepareRequest(\Symfony\Component\HttpFoundation\Request $request)
{
if (! $request instanceof Illuminate\Http\Request) {
$request = Illuminate\Http\Request::createFromBase($request);
}
$request->setUserResolver(function () use ($request) {
return $request->bearerToken();
})->setRouteResolver(function () {
return $this->currentRoute;
});
return $request;
}
};
This way you can have the simple resolution logic for getting the bearer token (don't include the AuthServiceProvider then).
(This requires PHP 7 anonymous classes; alternatively just extend to a regular class).
You do not need to change the register() function.
Just uncomment the following lines in bootstrap/app.php file:
$app->withEloquent();
$app->register(App\Providers\AppServiceProvider::class);
$app->register(App\Providers\AuthServiceProvider::class);
$app->routeMiddleware([
'auth' => App\Http\Middleware\Authenticate::class,
]);
And in app/Providers/AuthServiceProvider.php->boot(), it has default method to retrieve the authenticated user.
$this->app['auth']->viaRequest('api', function ($request) {
if ($request->input('api_token')) {
return User::where('api_token', $request->input('api_token'))->first();
}
});
You may use an API token in the request headers or query string, a bearer token on the request, or using any other approach your application requires.
After that, you may retrieve the authenticated user like this:
use Illuminate\Http\Request;
$app->get('/post/{id}', ['middleware' => 'auth', function (Request $request, $id) {
$user = Auth::user();
$user = $request->user();
//
}]);
The rebinding method will add an additional reboundCallbacks which this callback will be triggered right after the abstract is rebound. As long as your abstract is not rebound, the reboundCallbacks are not called. So, you can simply rebound your abstract, like so:
$this->app->rebinding('request', function ($app, $request) {
$request->setUserResolver(function () use ($app) {
$token = $this->request->bearerToken();
dd($token);
// do the rest
});
});
// REBOUND HERE
$this->app->instance('request', $this->app->make('request'));
// TEST
// $this->app->make('request')->user(); // output is $token
Try uncomment the rebound line above, your dd will not called at all.
Extra
You can use refresh method (to register reboundCallbacks) combined with extend method (to rebound) for cleaner code:
public function register()
{
parent::register();
$this->app->refresh('request', $this, 'overrideUserResolver');
// REBOUND HERE, JUST ANOTHER WAY TO REBOUND
$this->app->extend('request', function ($request) { return $request; });
// TEST
$this->app->make('request')->user();
}
public function overrideUserResolver($request)
{
$request->setUserResolver(function ($guard = null) use ($request) {
$token = $request->bearerToken();
dd($token);
// do the rest
});
}
I'm developing using PSR-7 (with Zend Expressive). I figured out the method
ServerRequestInterface::withAttribute()
and I was wondering why the object Response doesn't have one.
I'd like to pass metadata through middlewares after processing, on "response side".
Is there somehow to pass "attributes" on Response for post-processing? What's is the best way, following the architecture guidelines, to achieve that?
Best practise is using the request object to pass data between Middleware. The response is what is going out to the client and you want to keep this clean. The request lives only on the server and you can add (sensitive data) attributes to pass around. In case something goes wrong or you return a response early before removing the custom data, then it doesn't matter since your response is "clean".
Also if you need to pass data around: The Middleware is always executed in the order it gets from the config. This way you can make sure the request object in MiddlewareX contains the data set by MiddlewareY.
UPDATE: An example on how to pass data with the a request.
Middleware 2 sets an messenger object which Middleware 4 can use to set data which is required on the way out again.
<?php
namespace Middleware;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
class Middleware2
{
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next)
{
$messenger = new Messenger();
// Do something else before next middleware
if ($next) {
$response = $next($request->withAttribute(Messenger::class, $messenger), $response);
}
// Do something with the Response after it got back
// At this point the $messenger object contains the updated data from Middleware4
return $response->withHeader('Content-Language', $locale);
}
}
Middleware 4 grabs the messenger object and updates its values.
<?php
namespace Middleware;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
class Middleware4
{
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next)
{
$messenger = $request->getAttribute(Messenger::class);
$messenger->info('going in');
// Do something else before next middleware
if ($next) {
$response = $next($request->withAttribute(FlashMessenger::class, $messenger), $response);
}
// Do something with the Response after it got back
$messenger->info('going out');
return $response->withHeader('Content-Language', $locale);
}
}
The PSR-7 specification defines attributes only for server requests. They are mainly use to store metadata deduced from the incoming request so that they could be used later when you reach your domain layer.
On the other hand, a response is usually created in the domain layer and traverses back all the middleware stack before being actually sent to the client. So metadata added to a response would have no place where they could actually be used.
I guess that if you want to pass data from a inner middleware to an outer one, the best way is to use response headers.
Not sure if this is "best practice" but another possibility is to simply inject your data object into the middlewares.
Middleware 2 has a messenger object injected and sets some data on it:
<?php
namespace Middleware;
use Interop\Http\Server\MiddlewareInterface;
use Interop\Http\Server\RequestHandlerInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class Middleware2
{
private $messenger;
public function __construct(Messenger $messenger)
{
$this->messenger = $messenger;
}
public function process(
ServerRequestInterface $request,
RequestHandlerInterface $handler
): ResponseInterface {
$this->messenger->foo = 'bar';
$response = $handler->handle($request);
if ($this->messenger->foo = 'baz') {
return $response->withHeader('Really-Important-Header', 'Baz');
}
return $response;
}
}
Middleware 4 changes the data:
<?php
namespace Middleware;
use Interop\Http\Server\MiddlewareInterface;
use Interop\Http\Server\RequestHandlerInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class Middleware4
{
private $messenger;
public function __construct(Messenger $messenger)
{
$this->messenger = $messenger;
}
public function process(
ServerRequestInterface $request,
RequestHandlerInterface $handler
): ResponseInterface {
$this->messenger->foo = 'baz';
return $handler->handle($request);
}
}
You might even use one of the middlewares as the messenger.
Caveat: You have to make sure that both classes get constructed with the same messenger object. But that seems to be the case with most dependency injection containers.
Using dingo/api along with lucadegasperi/oauth2-server-laravel. Authenticating a user is fine and I get an access token back but any time I make another request I get the following error:
call_user_func() expects parameter 1 to be a valid callback, no array or string given
I'm using the Service Provider option listed in the dingo/api docs and it's definitely setting the user resolver (I'd var_dump'd the resolver in the setUserResolver method).
My OauthServiceProvider is below.
<?php namespace App\Providers;
use Dingo\Api\Auth\Auth;
use Dingo\Api\Auth\Provider\OAuth2;
use App\User\User;
use Illuminate\Support\ServiceProvider;
class OAuthServiceProvider extends ServiceProvider
{
public function boot()
{
$this->app[Auth::class]->extend('oauth', function ($app) {
$provider = new OAuth2($app['oauth2-server.authorizer']->getChecker());
$provider->setUserResolver(function ($id) {
return User::first();
// Logic to return a user by their ID.
});
$provider->setClientResolver(function ($id) {
// Logic to return a client by their ID.
});
return $provider;
});
}
public function register()
{
//
}
}
So turns out I was completely off in where I was looking. In config/api.php, in my auth settings I had
'oauth2' => Dingo\Api\Auth\Provider\OAuth2::class,
Should have just been
'oauth' => Dingo\Api\Auth\Provider\OAuth2::class,