问题
I'm trying to login my users with ajax with a new Laravel 5.3 project.
I've generated the auth routes, which got added to my web.php:
Auth::routes();
I have a html form with email, and password inputs and the csrf field. Then I also have this javascript file:
$("form.login").submit(function(e) {
e.preventDefault();
$.ajax({
method: "POST",
dataType: "json",
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content'),
},
data: $("form.login").serialize(),
url: "/login"
})
.done(function(data) {
console.log(data);
});
});
When I post it however, this shows up in my network tab:
It redirects back to the original page, without returning any data.
Why is it doing this? Does 5.3 not give json responses anymore?
回答1:
The Complete Solution:
Hi reinierkors,
I also tried to do the same with the 5.3 version, I finally solved it :) and the solution is very clean.
First, I created a new folder under App\Http\Controllers\Api called Auth, I did it just to add new auth controllers for the api so I can rewrite some functions, then I copied the auth controllers (LoginController, ForgotPasswordController, RegisterController) to this new folder.
In LoginController Class: I rewrited the functions that were making the redirects.
The first function: will be automatically called when the authentication return success.
The second function: will be automatically called when the authentication return error.
The last function: will be automatically called when the user has been locked out after trying 5 login attempts.
/**
* Send the response after the user was authenticated.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
protected function sendLoginResponse(Request $request) {
$this->clearLoginAttempts($request);
return response()->json(['SUCCESS' => 'AUTHENTICATED'], 200);
}
/**
* Get the failed login response instance.
*
* @return \Illuminate\Http\Response
*/
protected function sendFailedLoginResponse() {
return response()->json(['ERROR' => 'AUTH_FAILED'], 401);
}
/**
* Error after determining they are locked out.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
protected function sendLockoutResponse(Request $request) {
$seconds = $this->limiter()->availableIn(
$this->throttleKey($request)
);
return response()->json(['ERROR' => 'TOO_MANY_ATTEMPTS', 'WAIT' => $seconds], 401);
}
In RegisterController Class: I rewrited the functions that were making the redirects.
In the first function: I modified the validator response to return a more comfortable response (array) to work with.
The second function: will be automatically called when the registration return success.
/**
* Handle a registration request for the application.
*
* @param Request $request
* @return \Illuminate\Http\Response
*/
public function register(Request $request) {
$validator = $this->validator($request->all());
if($validator->fails())
return response()->json(['ERROR' => $validator->errors()->getMessages()], 422);
event(new Registered($user = $this->create($request->all())));
$this->guard()->login($user);
return $this->registered($request, $user)
?: redirect($this->redirectPath());
}
/**
* The user has been registered.
*
* @param Request $request
* @param mixed $user
* @return mixed
*/
protected function registered(Request $request, $user) {
return response()->json(['SUCCESS' => 'AUTHENTICATED']);
}
In ForgotPasswordController Class: I rewrited the function that was making the redirects.
I modified the reset link email function so we can get the messages and display as json instead of the redirects.
/**
* Send a reset link to the given user.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\RedirectResponse
*/
public function sendResetLinkEmail(Request $request)
{
$validator = Validator::make($request->only('email'), [
'email' => 'required|email',
]);
if ($validator->fails())
return response()->json(['ERROR' => 'VALID_EMAIL_REQUIRED'], 422);
// We will send the password reset link to this user. Once we have attempted
// to send the link, we will examine the response then see the message we
// need to show to the user. Finally, we'll send out a proper response.
$response = $this->broker()->sendResetLink(
$request->only('email')
);
if ($response === Password::RESET_LINK_SENT) {
return response()->json(['SUCCESS' => 'EMAIL_SENT'], 200);
}
// If an error was returned by the password broker, we will get this message
// translated so we can notify a user of the problem. We'll redirect back
// to where the users came from so they can attempt this process again.
return response()->json(['ERROR' => 'EMAIL_NOT_FOUND'], 401);
}
回答2:
For explanation about my mistake (the kind of same as op), see the edit history of this post.
How I solved it
with a little bit of help from @iSensical
Inside the app/Exceptions/Handler.php there is a unauthenticated function which, by default, knows if the request expects a json answer with the expectsJson() function.
The problem didn't came from Laravel by itself. It was, surprisingly, the human factor. I wrote a bad piece of code.
My ajax request did not used an intuitive header for Laravel.
I had this:
$http({
url : '{{ route('angular.auth.login.post') }}',
method : 'POST',
data : $.param($scope.user)+'&x-csrf-token='+CSRF_TOKEN,
headers : { 'Content-Type': 'application/x-www-form-urlencoded' }
})
[...]
We might have used a bad Content-Type.
The correct one was application/json like this:
headers : { 'Content-Type': 'application/json' }
来源:https://stackoverflow.com/questions/39675978/laravel-5-3-ajax-login