Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to bind user object to request in a middleware

i'm writing an application in Laravel Spark 1.0 (Laravel 5.2). I wrote a custom middleware for agent (api) authentication. This is the code:

<?php

namespace App\Http\Middleware;

use App\Agent;
use Closure;
use Illuminate\Http\Request;

class AgentAuth
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if( isset($request->token) &&  !empty($request->token) )
        {
            $agent = Agent::where('token', '=', $request->token)->first();

            if( $agent != NULL )
            {
                $team = $agent->Team()->first();
                $user = $team->User()->first();

                $request->merge(['team' => $team ]);
                $request->merge(['user' => $user ]);

                return $next($request);
            }
            else {
                return response('Unauthorized 2.', 401);
            }

        }
        else {
            return response('Unauthorized 1.', 401);
        }
    }
}

In the default laravel authentication the user object is injected in the request (see laravel docs): https://laravel.com/docs/5.2/authentication#retrieving-the-authenticated-user

So you can retrieve the user using:

$request->user();

Spark obviously use this method to check if user subscription is valid (laravel\spark\src\Http\Middleware\VerifyUserIsSubscribed):

if ($this->subscribed($request->user(), $subscription, $plan, func_num_args() === 2)) {
            return $next($request);
        }

And it's not working because, with my middleware, you can retrieve the user using: $request->user; but not with the laravel defaults $request->user();

How should i inject the user object into the request?

Thank you in advance

EDIT:

Laravel in the service provider (Illuminate\Auth\AuthServiceProvider@registerRequestRebindHandler)

Use this code to bind object user to the request:

/**
     * Register a resolver for the authenticated user.
     *
     * @return void
     */
    protected function registerRequestRebindHandler()
    {
        $this->app->rebinding('request', function ($app, $request) {
            $request->setUserResolver(function ($guard = null) use ($app) {
                return call_user_func($app['auth']->userResolver(), $guard);
            });
        });
    }

I tried to insert this code, with the appropriate correction, in the middleware but i can't figure out how to make it work.

like image 716
eldblz Avatar asked Sep 09 '16 15:09

eldblz


3 Answers

I don't have a copy of Spark to try this & ensure what I'm doing is correct for you, but I think this will help:

1) An assumption - I believe you are saying that yes, this line will get you the user you want:

$user = $team->User()->first();

and you merely want to bind it to the request so that you can access this user later in your app via:

$request->user()

2) If this is true, then all I did was simplify the code you provided to add:

$request->merge(['user' => $user ]);

//add this
$request->setUserResolver(function () use ($user) {
    return $user;
});

// if you dump() you can now see the $request has it
dump($request->user());

return $next($request);

I also $request->user() in the route closure, and it is there.

The app rebinding was a little strange to me, and didn't seem necessary. I'm not sure that anything would really need this for what you are doing.

like image 132
jmadsen Avatar answered Nov 17 '22 16:11

jmadsen


This is a very useful question. I was having trouble with the selected solution though. In my middleware I could successfully see $request->user(), however it was failing when using gates, namely in the Access/Gate class:

protected function raw($ability, $arguments = [])
{
    if (! $user = $this->resolveUser()) {
        return false;
    }

    // ...

This function is always returning false :/

So I did it as suggested here (http://laravel-recipes.com/recipes/230/setting-the-currently-authenticated-user), namely:

$usr = new User();
$usr->setAttribute('id', $request->user_id);
Auth::setUser($usr);

And it appears to be working without using setUserResolver().

Thanks

like image 42
mils Avatar answered Nov 17 '22 14:11

mils


You could use the auth system if that model implements the right interface, to log them in for the request.

Auth uses a rebinder to assign the userResolver on request. (So you get $request->user() from it). Check Illuminate\Auth\AuthServiceProvider@registerRequestRebindHandler to see how its setting that resolver.

$request->setUserResolver(....)
like image 3
lagbox Avatar answered Nov 17 '22 15:11

lagbox