Reputation: 192
I'm using the 'HTTP Basic Authentication' feature of laravel. I want to customize the error message which is generated from laravel if the entered credentials are wrong.
Is it possible to catch the 401 Error which is generated when HTTP Auth fails?
Hope you can help me.
Regards
Upvotes: 1
Views: 3738
Reputation: 41
Here's how I did it:
Route::filter('auth.basic', function()
{
$message = [
"error" => [
"code" => 401,
"message" => "Invalid Credentials"
]
];
$headers = ['WWW-Authenticate' => 'Basic'];
$response = Auth::basic();
if (!is_null($response)) {
return Response::json($message, 401, $headers);
}
});
If you look in Illuminate\Auth\Guard you'll find the basic method that's called by Auth::basic(). It either returns null or a Response object via the getBasicResponse method.
/**
* Attempt to authenticate using HTTP Basic Auth.
*
* @param string $field
* @param \Symfony\Component\HttpFoundation\Request $request
* @return \Symfony\Component\HttpFoundation\Response|null
*/
public function basic($field = 'email', Request $request = null)
{
if ($this->check()) return;
$request = $request ?: $this->getRequest();
// If a username is set on the HTTP basic request, we will return out without
// interrupting the request lifecycle. Otherwise, we'll need to generate a
// request indicating that the given credentials were invalid for login.
if ($this->attemptBasic($request, $field)) return;
return $this->getBasicResponse();
}
Here's getBasicResponse:
/**
* Get the response for basic authentication.
*
* @return \Symfony\Component\HttpFoundation\Response
*/
protected function getBasicResponse()
{
$headers = array('WWW-Authenticate' => 'Basic');
return new Response('Invalid credentials.', 401, $headers);
}
Here we finally have our 'Invalid credentials.' text that we're looking to change. We see it's just returning an instance of a Symphony response with a 401 status code and the Basic Auth header and null in all other occasions. So, we'll just check for a non-null result and if we get one, return our new response as shown above.
Also, if you want it to actually be stateless you should use:
Auth::onceBasic()
I don't know how future proof this method is, but it works as of Laravel 4.1.
Final results once again:
Route::filter('auth.basic', function()
{
$message = [
"error" => [
"code" => 401,
"message" => "Invalid Credentials"
]
];
$headers = ['WWW-Authenticate' => 'Basic'];
$response = Auth::onceBasic();
if (!is_null($response)) {
return Response::json($message, 401, $headers);
}
});
Upvotes: 4
Reputation: 22872
Try to capture 401
error and return cusom view?!
App::error(function($exception, $code)
{
switch ($code)
{
case 401:
return Response::view('errors.403', array(), 401);
case 403:
return Response::view('errors.403', array(), 403);
case 404:
return Response::view('errors.404', array(), 404);
case 500:
return Response::view('errors.500', array(), 500);
default:
return Response::view('errors.default', array(), $code);
}
});
I think, code is pretty straightforward and self explaining.
Just to note, $errors
variable is of type MessageBag
and is available in views even if you don't set it explicitly! Which is great! :)
I used simple routing, place it into your controllers
app/routes.php
Route::get('auth', function()
{
$creds = array(
'email' => Input::get('email'),
'password' => Input::get('password'),
);
if ( ! Auth::attempt($creds))
{
$errors = new MessageBag;
$errors->add('login', trans("Username and/or password invalid."));
return Redirect::to('/')->withErrors($errors);
}
return Redirect::to('/protected/area');
});
Route::get('/', function(){
return View::make('hello');
});
// app/views/hello.php
@if($errors->has('login'))
{{ $errors->first('login') }}
@endif
Upvotes: 4