RadicalActivity's avatar

How to do a 100% custom authentication with Laravel 5.x?

Hey,

I'm looking for a way to create a custom login authentication with Laravel. I have a login form that look like this:

{!! Form::open(array('route' => array('login/post'), 'class' => 'form-horizontal')) !!}
    <div class="form-group">
        <div class="col-xs-12">
            {!! Form::text('username-wl', '', ['class' => 'form-control', 'placeholder' => 'Your login name...']) !!}
            @if ($errors->has('username-wl'))<span class="help-block" style="color:red;">{!!$errors->first('username-wl')!!}</span>@endif
        </div>
    </div>
    <div class="form-group">
        <div class="col-xs-12">
            {!! Form::password('password-wl', ['class' => 'form-control', 'placeholder' => 'Your password...']) !!}
            @if ($errors->has('password-wl'))<span class="help-block" style="color:red;">{!!$errors->first('password-wl')!!}</span>@endif
        </div>
    </div>
    <div class="form-group form-actions">
        <div class="col-xs-8">
        </div>
        <div class="col-xs-12 text-right">
            <button type="submit" id="login" class="btn btn-effect-ripple btn-sm btn-primary"><i class="fa fa-check"></i> &nbsp; Let's Go</button>
        </div>
    </div>
{!! Form::close() !!}

Now this above code works perfectly.

I'm also doing an error checking with Requests. So I have a file called: LoginRequest.php, that looks like this:

<?php namespace App\Http\Requests;

use App\Http\Requests\Request;

class LoginRequest extends Request {

    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
          'user' => 'required',
          'password'    => 'required'
        ];
    }

}

This validation works prefectly. When I pust the login button and nothing is filled, it gets me the error messages.

I'm calling this Request from one of my controller's method:

    public function login(LoginRequest $request)
    {
        return $request;
    }

Now, what I want to do is, checking when the post is submitted and there are no errors, I should be able to run custom functions on the user that's logged in.

I have tried to do this via a Middleware, however it seemd like that the Middleware is running before the Requests, so if the form is empty for example, the Middleware - and my custom functions - will still run.

I want something like this logic:

User submits info -> incorrect error messages shown (if applies) -> Custom functions run -> if username & password is correct then redirect and login, else -> redirect to login page.

Can someone give me any direction what am I missing here?

Would appreciate it a lot!

0 likes
10 replies
davorminchorov's avatar

I am not sure if form requests work the same way in middleware classes (I've never tried it but I'd love to hear more about it) but you can do something like this in the controller:

 public function login(LoginRequest $request)
{
    // you can use the auth() helper or an object of the Guard class here too. Choose your way
    if(!Auth::attempt($request->only('user', 'password'))
    {
        return redirect('login') // or return back();   
    }

    return redirect('home');
}
RadicalActivity's avatar

Thanks for your input Ruffles.

Is there any other way that isn't using Guard class? I'd like to add a lot of other custom functions there, like storing visitor info in the DB, doing some other type of login checks, etc.

So basically you want to say that I can do my stuff within the controller and I'll be fine if I leave out middlewares?

davorminchorov's avatar

Maybe the Guard Contract/Interface? Laravel is full of contracts! Constructor injection if you are going to use it in multiple methods.

Well, there are a lot of ways to do this, some people might do it in a middleware, some in a trait, someone else in the controller, or even a service class.

What's the best way? I don't know, everyone does it differently.

I'd personally do it in the controller or a service class.

layer7's avatar

Hey,

If all you need to be able to do is run custom functions on authentication requests, can't you simply add that logic into the handle() method of App\Http\Middleware\Authenticate.php? I do think this method is better kept lightweight because this is probably triggered on every request (and not only on login requests). Extra logic for failed login attempts could be added like so:

public function handle($request, Closure $next)
{
    if ($this->auth->guest()) {
       if ($request->ajax()) {
            return response('Unauthorized.', 401);
        } else {
            # extra logic on failed attempt => log something
            Log::warning('Detected a failed login attempt');
            return redirect()->guest('auth/login');
        }
    }

    return $next($request);
}

The extra logic you have to do for valid login attempts can probably be added to the handle() method in App\Http\Middleware\RedirectIfAuthenticated.php.

public function handle($request, Closure $next)
{
    if ($this->auth->check()) {
        # extra logic => log something
        Log::info('Successful login attempt received');
        return redirect('/home');
    }

    return $next($request);
}
RadicalActivity's avatar

Thanks for your suggestions Ruffles, these ideas sounds great!

So if I'm doing it on the controller side, it won't interfere with my Request class then?

martinbean's avatar

@RadicalActivity Why do you want to do “100% custom authentication” in a framework like Laravel that offers you multiple interfaces and points to add your own code in the authentication process?

Look at the AuthenticatesUsers trait. There are numerous methods in there that can be overridden in your AuthController. Particularly line 81 where it checks for a method called authenticated(). You can define this method (which would receive the Request instance and the authenticated user) that you can run any post-login routines on.

There really is no reason to reinvent the wheel. If you want to write 100% custom code, then a framework isn’t for you.

2 likes
RadicalActivity's avatar

@martinbean thanks for your answer!

I basically want a code that doesn't rely on the Auth class. I don't really understand that class, because I am working with a database that is not created with Laravel. Do you know any good tutorials on how to implement my custom checkings to the Auth class and use it with a non-laravel created DB?

layer7's avatar

@RadicalActivity I presume you just want to use a database without the Eloquent models then? In that case, just add a new database definition in config/database.php like this:

'connections' => [
    // add something like this:
    'extradb' => [
        'driver'    => 'mysql',
        'host'      => env('EXTRADB_HOST') ?: 'localhost',
        'database'  => env('EXTRADB_DATABASE') ?: 'external_db',
        'username'  => env('EXTRADB_USERNAME') ?: 'homestead',
        'password'  => env('EXTRADB_PASSWORD') ?: 'secret',
        'charset'   => 'utf8',
        'collation' => 'utf8_unicode_ci',
        'prefix'    => '',
        'strict'    => false,
    ],
],

Then you should be able to use the Query Builder by doing something like this in your code:

$users = DB::connection('extradb')->table('users')->select('firstname', 'lastname', 'email')->get();
RadicalActivity's avatar

@layer7 thanks for your input! Yeah it's already set for me. What I basically want is to validate the user somewhere after showing the possible error messages to him.

maverickrush1's avatar

@RadicalActivity Best suggestion is to scrap the application and write it insome other stack. It's a pretty good framework but i would suggest that in theses days of NODE.js and python it isn't a best way to develop things in php anymore.

Please or to participate in this conversation.