2

I try to create login form with Ajax using Laravel 5.2 Auth.

$(document).ready(function(){
$.ajaxSetup({
  headers: {
    'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
  }
});

$('#login').on('click',function(e){
e.preventDefault(); 

var formData = {
    email: $('#email').val(),
    password: $('#password').val(),
}
    $.ajax({
        type: "POST",
        url: "/login",
        data: formData,
        success: function (data) {
           location.reload();
        },
        error: function (data) {

        }
    });

});

})enter code here

Laravel default login function:

public function login(Request $request)
{
$this->validateLogin($request);

// If the class is using the ThrottlesLogins trait, we can automatically throttle
// the login attempts for this application. We'll key this by the username and
// the IP address of the client making these requests into this application.
$throttles = $this->isUsingThrottlesLoginsTrait();

if ($throttles && $lockedOut = $this->hasTooManyLoginAttempts($request)) {
    $this->fireLockoutEvent($request);

    return $this->sendLockoutResponse($request);
}

$credentials = $this->getCredentials($request);

if (Auth::guard($this->getGuard())->attempt($credentials, $request->has('remember'))) {
    return $this->handleUserWasAuthenticated($request, $throttles);
}

// If the login attempt was unsuccessful we will increment the number of attempts
// to login and redirect the user back to the login form. Of course, when this
// user surpasses their maximum number of attempts they will get locked out.
if ($throttles && ! $lockedOut) {
    $this->incrementLoginAttempts($request);
}

return $this->sendFailedLoginResponse($request);
}

/login return index page as a response. I need json response about error messages or success message. It is said that changing Laravel core functions is not advisable. Then how can I get it?

Nigar Jafar
  • 144
  • 2
  • 3
  • 12

5 Answers5

4

As I understood Your code example is just copy of AuthenticatesUser trait.

So to avoid big changes and make it work, just replace default controller code in app/Http/Controllers/LoginController.php with this:

<?php

namespace App\Http\Controllers\Auth;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class LoginController extends Controller
{
    public function __construct()
    {
        $this->middleware('guest', ['except' => 'logout']);
    }

    protected function username() {
        return 'email';
    }

    public function login(Request $request)
    {
        $credentials = $request->only($this->username(), 'password');
        $authSuccess = Auth::attempt($credentials, $request->has('remember'));

        if($authSuccess) {
            $request->session()->regenerate();
            return response(['success' => true], Response::HTTP_OK);
        }

        return
            response([
                'success' => false,
                'message' => 'Auth failed (or some other message)'
            ], Response::HTTP_FORBIDDEN);
    }

    public function logout(Request $request)
    {
        Auth::logout();
        $request->session()->flush();
        $request->session()->regenerate();

        return redirect('/');
    }
}



js part can keep the same:

$.ajax({
    type: "POST",
    url: "/login",
    data: formData,
    dataType:'json',
    success: function (response) {
       if(response.success) {
         window.location.replace('/dashboard');
       }
    },
    error: function (jqXHR) {
      var response = $.parseJSON(jqXHR.responseText);
      if(response.message) {
        alert(response.message);
      }
    }
});

but I personally prefer to handle not the button that does submit, but the form generally, to prevent this happen when user press enter button than just click on the login button.

check this example:

html part:

<form class="login" action="{{ url('/login') }}" method="post" data-type="json">
  <input type="text" name="email">
  <input type="password" name="password">
  <button type="submit">login</button>
</form>

js part:

$(function() {

  $.ajaxSetup({
    headers: {
      'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
    }
  });

  $('form.login:first').on('submit', function(e){
    e.preventDefault(); 
    
    var $this = $(this);

    $.ajax({
        type: $this.attr('method'),
        url: $this.attr('action'),
        data: $this.serializeArray(),
        dataType: $this.data('type'),
        success: function (response) {
           if(response.success) {
             location.reload();
           }
        },
        error: function (jqXHR) {
          var response = $.parseJSON(jqXHR.responseText);
          if(response.message) {
            alert(response.message);
          }
        }
    });
  });

});
num8er
  • 18,604
  • 3
  • 43
  • 57
  • it has 500(Internal Server Error) but i can't figure out where it is. I send it to url: "/loginajax" (not /login) , and in route send it LoginController@login function because of understanding what it does exactly , but i have not idea where error is – Nigar Jafar Jan 20 '17 at 20:47
  • send it to `/login` not `/loginajax` error 500 should be something like route not found. – num8er Jan 20 '17 at 20:56
  • @NigarJafar I've updated my answer, please check. If You it still does not work, so add me in skype: `anarjafarov` and let's debug – num8er Jan 20 '17 at 21:14
  • Well, I get error "Unexpected token < in JSON token at position 0", but in case of email/password are true, while reloading page manually i see it is logged in. Searched about this error and it is said that "The Unexpected token < in JSON token at position 0 means that there are hidden/special characters in the link " As far I understand it consider current link , but there is not any special charachter in it. – Nigar Jafar Jan 20 '17 at 21:15
  • @NigarJafar because of You're not using normal IDE like: PHP Storm, Netbeans, Zend Studio, or at least editors: atom, sublime. So it's problem of BOM symbol in the beginning of file that happens because of non file proper encoding, it's not visible but it affects on json parser of browser. – num8er Jan 20 '17 at 21:18
  • I use Sublime Text 2 . slug comes from database and data is form of collation utf8_general_ci . Can collation type affect it? – Nigar Jafar Jan 20 '17 at 21:28
1

You can try adding in jquery

dataType: 'JSON'

or Try to store in Session and use

Redirect::back()

or

return redirect($this->loginPath())
       ->withInput($request->only('email', 'remember'))
       ->withErrors([
             'email' => $this->getFailedLoginMessage(),
        ]);
1

Please try this one

use Validator;
use Auth;


public function postUserLogin(Request $request) {
    $credentials = array_trim($request->only('email', 'password'));
    $rules = ['email' => 'required|email|max:255',
        'password' => 'required'
    ];

    $validation = Validator::make($credentials, $rules);
    $errors = $validation->errors();
    $errors = json_decode($errors);
    if ($validation->passes()) {
        if (Auth::attempt(['email' => trim($request->email),
                    'password' => $request->password,
                        ], $request->has('remember'))) {


            return response()->json(['redirect' => true, 'success' => true], 200);
        } else {
            $message = 'Invalid username or password';

            return response()->json(['password' => $message], 422);
        }
    } else {
        return response()->json($errors, 422);
    }
}
ToJ
  • 155
  • 7
  • use response object to set statuses it's more safe than defining numbers: `Response::HTTP_FORBIDDEN` ;) – num8er Jan 20 '17 at 11:57
  • Should I add this code some controller or \vendor\laravel\framework\src\Illuminate\Foundation\Auth\AuthenticatesUsers.php ? Is there any difference? – Nigar Jafar Jan 20 '17 at 12:38
  • @NigarJafar in fact You are free to choose if You know how Laravel works. In Your case I see You've own code copy-pasted or from somewhere (or written by someone before You) that You try to use. If You want just send the form fields and get json-ic response and to reload the page, just respond from Your controller's `login` action with json response and status, where 2xx series is handled by `success`, 4xx-5xx by `error`. – num8er Jan 20 '17 at 14:35
  • @num8er I showed that function is come with Laravel Auth, I didn't write it myself. I'm interested in that I should change this function or write on my own function. Which one is preferable, because some people say that changing Laravel default code is not good. – Nigar Jafar Jan 20 '17 at 19:06
  • @NigarJafar in world of anything changing vendor-ed code, or code of package locally is not good. Because of after updating packages or deploying the code and running `composer install` it will download original code, so Your system will not work. – num8er Jan 20 '17 at 19:46
  • @NigarJafar as I know this code in Your question is from `AuthenticatesUser` trait. So You can have copy of default: `app/Http/Controllers/Auth/LoginController.php` and copy of `AuthenticatesUser.php` and remake it to be used for Your ajax needs. – num8er Jan 20 '17 at 19:50
  • @NigarJafar, I've just updated my answer, please check latest code, there I'm showing quick solution. – num8er Jan 20 '17 at 20:23
0

Add as follows

  /**
     * Handle a login request to the application.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\Response|\Illuminate\Http\JsonResponse
     *
     * @throws \Illuminate\Validation\ValidationException
     */
    public function login(Request $request)
    {
        $this->validateLogin($request);

        if ($this->hasTooManyLoginAttempts($request)) {
            $this->fireLockoutEvent($request);
            return response()->json( $this->sendLockoutResponse($request));
        }
        if ($this->attemptLogin($request)) {
            return response()->json( $this->sendLoginResponse($request) );
        }

        $this->incrementLoginAttempts($request);
        return response()->json($this->sendFailedLoginResponse($request));
    }
Arshid KV
  • 9,631
  • 3
  • 35
  • 36
0

In your controller return the response like this if successful return response()->json(['success' => 'Login successfully!']); if getting any error return response()->json(['success' => 'Login successfully!']);

and In your .js file you have to apply conditions like this

function login(url) {

    event.preventDefault();
$.ajax({
      type: 'POST',
      url: url,
      data: $('#login-form').serialize(),
      success: function (response) {
  
      
        if (response.hasOwnProperty('errors')) {
          var loginErrorsMessage = response.errors;

          console.log(loginErrorsMessage); //your all errors 
       }
       if (response.hasOwnProperty('success')) {

          var successMessage = (response.success) 

         console.log(successMessage); //your message
          window.location.href = getBaseURL() + '/dashboard';
        }

});
}

your login form will be like this

 <form id="login-form" class="space-y-4 md:space-y-6">
  @csrf
      <div>
        <label for="email" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Your email</label>
        <input type="email" name="email" id="email" class="bg-gray-50 border border-gray-300 text-gray-900 sm:text-sm rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" placeholder="name@company.com" required="">
                                 
      </div>
      <div>
         <label for="password" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Password</label>
          <input type="password" name="password" id="password" placeholder="••••••••" class="bg-gray-50 border border-gray-300 text-gray-900 sm:text-sm rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" required="">
            
     </div>
     <button id="login_btn"  onclick="login('{{URL::to("custom-login")}}')"  class="w-full bg-indigo-600 hover:bg-primary-700 focus:ring-4 focus:outline-none focus:ring-primary-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center text-white dark:bg-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800">Sign in</button>
      <p class="text-sm font-light text-gray-500 dark:text-gray-400">
                            Don’t have an account yet? <a href="{{url('register')}}" class="font-medium text-primary-600 hover:underline dark:text-primary-500">Sign up</a>
      </p>
 </form>