Super Quick Tutorial: Auditing Requests and Responses in Laravel using HTTP Middleware

So for whatever reason you want to track the usage of your app by your users. We’re going to do it using middleware, now for the purposes of this I’m not going to separate things out properly how we would normally, because this is a super quick tutorial.

The Problem / Situation

You need to track your app usage for audit purposes, or some other legitimate purpose.

The Super Quick Solution

The simplest possible implementation would a new middleware called AuditRequest which would be in App\Http\Middleware (then register it through the HttpKernel and invoke it wherever you need it).

I’ll assume you have an audits table and a corresponding Audit Model which you’ve created, set the relevant fillable attributes etc.

/**
 * Handle an incoming request.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  \Closure  $next
 * @param  string|null  $guard
 * @return mixed
 */
public function handle($request, Closure $next, $guard = null)
{

    $response = $next($request);

    // I've pulled this out at this point, because of a point I raise in the Also Consider section
    $payload = json_encode($request->all());
    Audit::create([
            'user_id' => $userId,
            'method' => $request->getMethod(),
            'url' => $request->url(),
            'route' => $request->route()->getName(),
            'payload' => $payload,
            'ip_address' => $request->ip(),
            'user_agent' => $request->userAgent() ?? 'Not Provided'
        ]);
    return $response;

Also Consider

  1. Cleaning! This could log a whole load of data, and you may well want to periodically clean it, simply moving records into another data source (S3 bucket / DigitalOcean Space / MongoDb etc) and removing them from your active database can be handy
  2. GDPR / Data Protection Act / PCI-DSS compliance this can be a really sticky wicket, this middleware will log everything from your payload, you so may want the ability to clean / anonymise etc.
  3. Usefulness of the information; what we’ve done above might not be that useful, so you may end up with something a bit more like

GDPR / Data Protection Act / PCI-DSS compliance

There are going to be times when you don’t want to store the payload, in this instance you can do something like

In your controller, when you have a request that you don’t want to track

AuditRequest::doNotTrackPayload();

In your middleware;

static $trackPayload = true;

public static function doNotTrackPayload()
{
    static::$trackPayload = false;
}

In the handler method above;

$payload = null;
if (static::$trackPayload === true){
    $payload = json_encode($request->all());
}

Now if the static method doNotTrackPayload is called, we’re simply going to store the $payload as null thus not storing, for example, passwords, card details or anything else.

Usefulness of the Information

If you’ve got a lot of audits running through, you might want something a bit easier to read; so you might want something like the below to put a friendly message as to what they did, something like “Updated their Profile” which can be called from your controller.

For me personally, I put methods on the base Controller for parsing this information around. And you may well want to use proper SOLID techniques to implement all the above. Naturally in these Super Quick Tutorials, I’m giving you the bare minimum to achieve the job, so that you can work within your own parameters (interfaces, dependency injection, testability, etc) which are outside of the scope of these articles.

public static function setMessage(string $message)
{
    static::$message = $message;
}

I'd love to hear your opinion on what I've written. Anecdotes are always welcome.

This site uses Akismet to reduce spam. Learn how your comment data is processed.