There is some option on Laravel that we allow Laravel to create a token and test it on server side to pull up CSRF attacks.
I found this on Laravel website, But didn't say how to check from Controller that is an attack or from a native and real page.
How to check the token (CSRF) on controller?
Answer for Laravel 5
In Laravel 5 middleware replaces filters. This is also true for CSRF. The middleware is enabled by default and is handled in App\Http\Middleware\VerifyCsrfToken.
It can be disabled by removing App\Http\Middleware\VerifyCsrfToken in App\Http\Kernel. And if moved to $routeMiddleware...
protected $routeMiddleware = [
'auth' => 'App\Http\Middleware\Authenticate',
'auth.basic' => 'Illuminate\Auth\Middleware\AuthenticateWithBasicAuth',
'guest' => 'App\Http\Middleware\RedirectIfAuthenticated',
'csrf' => 'App\Http\Middleware\VerifyCsrfToken',
];
... it can be used conditionally by adding it to a route:
Route::post('foo', ['middleware' => 'csrf', 'uses' => 'BarController#foo']);
Or in the controllers constructor:
public function __construct(){
$this->middleware('csrf');
}
Assuming you use laravel 4.x:
You don't need to check this in your controller. defining the before parameter tells laravel to check this automaticly.
Route::post('profile', array('before' => 'csrf', function(){
/* CSRF validated! */
}));
If you want to do something when the token is incorrect, you can change the filter in app/filters.php. This one:
Route::filter('csrf', function()
{
if (Session::token() != Input::get('_token'))
{
throw new Illuminate\Session\TokenMismatchException;
}
});
Related
I have created a custom middleware to check if $request->wantsJson() then it should allow the route to call the function. The order would be
1. Check for JSON
2. Check Auth
How can I implement the middle wares in this order? I have tried the following but its not working
Route::group(['middleware' => ['auth:api', 'json']], function () {
Route::group(['prefix' => 'V1'], function () {
Route::post('logout', 'API\V1\AuthController#logout');
});
});
Did you register the middleware in App\Http\Kernel.php route middleware?
https://laravel.com/docs/master/middleware#assigning-middleware-to-routes
protected $routeMiddleware = [
// ...
'json' => \App\Http\Middleware\CheckForJson::class,
];
There is also an additional array for forcing the priority (order) of non-global middleware.
https://laravel.com/docs/master/middleware#sorting-middleware
protected $middlewarePriority = [
// ...
\App\Http\Middleware\CheckForJson::class,
];
I have been working on a multi-tenant app and I'm trying to set up the routes in sub-domains according to the documentation:https://laravel.com/docs/5.7/routing#route-group-sub-domain-routing
In my web.php route file, I have something like this:
Route::domain('{account}.example.test')->group(function () {
Route::get('/home', 'HomeController#index')->name('home');
});
Right now, the problem is using named routes in blade, but I suppose I may run into the same problem eventually in my Controllers.
Whenever I try to used a named route like this:
Blade Code
Home
I get the following error:
Missing required parameters for [Route: home] [URI: home]. (View: /home/vagrant/Code/example/resources/views/example.blade.php)
I have found a way for solving this, you just have to:
Home
I also "solved" this using a helper...
if (! function_exists('acctRoute')) {
function acctRoute($name = '')
{
return route( $name, request('account'));
}
}
So I can use it like:
Home
But I'm still wondering if there's a cleaner way to do this, maybe with some middleware that always injects the parameter?
This is my answer to my own question in case anyone needs this in the future:
From here I noticed that you can set default values for all routes under a middleware:
https://laravel.com/docs/5.7/urls#default-values
So... This is what I ended up doing
First create the middleware:
php artisan make:middleware MyMiddleware
Then update the handle method inside the created middleware as in the documentation example:
public function handle($request, Closure $next)
{
URL::defaults(['account' => request('account')]);
return $next($request);
}
Then register the Middleware in Kernel.php
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
'mymiddle' => \App\Http\Middleware\MyMiddleware::class,
];
Then use it as any other middleware in your routes files:
Route::domain('{account}.example.test')->middleware('mymiddle')->group(function () {
Route::get('/home', 'HomeController#index')->name('home');
});
And finally, use the route helper function as usual:
Home
You could share the account (subdomain) variable across all views:
// AppServiceProvider
public function boot()
{
View::share('subdomain', request('account'));
}
// blade
Home
Another approach could use a service container binding:
// AppServiceProvider
$this->app->bind('account.route', function () {
return route('home', request('route'));
});
// blade
Home
I'm trying to restrict the access of routes to only some types of users in my site that I'm writing with Laravel 5.7, right now I'm trying to do it with middlewares.
For each user's level I have a middleware with this code(with a variation on the type):
public function handle($request, Closure $next)
{
if(Auth::user()->type==3)
return $next($request);
else
return redirect()->route('dashboard');
}
And in the kernel.php file, I have them written like this:
protected $routeMiddleware = [
...
'teacher' => \App\Http\Middleware\RedirectIfTeacher::class,
...
]
In my application each user has a level, which starts from 1 to 5, but each level has individual views and some shared views, but I can't manage to redirect views for more than just one type of user because I can't make them work when I use more than one middlewares on a route (or routes) that are shared with more than two types of users.
When I try it justs ignores the second or more middlewares and redirects to the route dashboard which is the route for redirecting if the type of user can't enter the desired view.
Right now I've tried with this code:
Route::group(['middleware' => ['administrator','teacher','student']], function(){
And with this code:
Route::group(['middleware' => ['administrator' OR 'teacher' OR 'student']], function(){
Also I tried with this style:
Route::group(['middleware' => ['administrator|teacher|student']], function(){
Without getting any luck, is there anything what am I doing wrong? or is there a better way to do what I'm trying to achieve, thanks in advance!.
I'm using below code and it worked:
Route::group(['middleware' => ['administrator','teacher','student']], function() {});
1 In the kernel.php file, have you got all of the keys assigned with your middlewares ? For example:
protected $routeMiddleware = [
...
'administrator' => \App\Http\Middleware\RedirectIfAdmin::class,
'teacher' => \App\Http\Middleware\RedirectIfTeacher::class,
'student' => \App\Http\Middleware\RedirectIfStudent::class,
...
]
2 Try to check the user vars before the if in your handle().
dd(Auth::user()->type);
You need to pass an array to it I guess
Route::group(['middleware' => ['administrator','teacher','student']], function() {});
If that doesn't work you have to split them I guess
Route::group(['middleware' => 'administrator'], function () {
Route::group([ 'middleware' => 'teacher'], function() {
Route::group([ 'middleware' => 'student'], function() {
});
});
});
I am new to Laravel but fell in love with the framework and decided to use it for my project.
I have a field active and by default I've set it to 0. In the Attempt() method, I've set $credentials['active'] = 1. When I logout and login again, this works fine.
But when I register a user, it automatically logs the user in without checking active field.
I assume you are using the AuthenticatesAndRegistersUsers trait in your controller.
The registration is carried by the postRegister() method in that trait, which calls the login() method after creating a new user.
You can override this method in your controller and call the login() method only when the active field is true. So, your postRegister() method will be something like:
public function postRegister(Request $request)
{
$validator = $this->registrar->validator($request->all());
if ($validator->fails())
{
$this->throwValidationException(
$request, $validator
);
}
$user = $this->registrar->create($request->all());
if ($request->get('active')) {
$this->auth->login($user);
}
return redirect($this->redirectPath());
}
In registersUsers.php replace the line:
Auth::guard($this->getGuard())->login($this->create($request->all()));
With the following:
$this->create($request->all());
This worked for me, I use Laravel 5.2
I would avoid adding the active field to the credentials - this is an authorisation issue rather than an authentication one.
For this, I'd use a middleware to check if a logged-in user is active or inactive.
In 5.3, the middleware would look like this:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Auth;
class RedirectIfInactive
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if ( $user = Auth::guard('web')->user() ) {
if ( ! $user->active )
return redirect(route('account_inactive'));
}
return $next($request);
}
}
This middleware then has to be registered inside Kernel.php:
protected $routeMiddleware = [
'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'inactive' => \App\Http\Middleware\RedirectIfInactive::class,
];
And then finally we protect all our routes with it:
Route::get('inactive', ['as' => 'account_inactive', function () {
return view('inactive');
}]);
Route::group(['prefix' => 'admin', 'namespace' => 'Admin', 'middleware' => 'inactive'], function () {
Route::get('/', ['as' => 'admin.home', 'uses' => 'AdminController#index']);
});
The advantage of this approach of course is that we can display a more relevant error message than the general 'These credentials do not match our records' that people with bad auth details get. So the user would know it's not their fault they can't log in.
Anyway, with the approach in the accepted answer, ensure you have done the same for when the user successfully resets their password as they are also auto-logged in then.
For future reference, you could just override the registered method and inside it, destroy all sessions by using Auth::logout. The user will by default be redirected to Login page
I defined a resource route group
Route::group(['prefix' => 'api/v1'], function() {
Route::resource('words', 'WordController');
});
and I created a controller for all that routes. I want to set basic authentication for all requests so I added to the constructor of WordController: $this->beforeFilter('auth.basic'); But there is no effect. I still can get all words without any username and password provided. Does someone know why?
class WordController extends ApiController {
protected $wordTransformer;
function __construct(WordTransformer $wordTransformer)
{
$this->wordTransformer = $wordTransformer;
$this->beforeFilter('auth.basic');
//$this->middleware('auth.basic');
}
public function index()
{
$words = Word::all();
return $this->respond([
'words' => $this->wordTransformer->transformCollection($words->all())
]);
}
}
If you are using laravel 5, you can use middleware that replace filter. Using middleware is becoming the preferred practice and way of thinking about decorating your routes. Why your code not working because auth.basic is a type of middleware not filter.
You can attach the middleware in controller since you are using Route::group.
See the code below how to attach it.
Route::group(['prefix' => 'api/v1', 'middleware' => 'auth.basic'], function() {
Route::resource('words', 'WordController');
});
You can see at the above code use middleware name "auth.basic". How do you know the middleware. Before you can use the middleware, you must register the middleware by define the middleware in /app/Http/Kernel.php. If you open that file you can see the code below.
/**
* The application's route middleware.
*
* #var array
*/
protected $routeMiddleware = [
'auth' => 'App\Http\Middleware\Authenticate',
'auth.basic' => 'Illuminate\Auth\Middleware\AuthenticateWithBasicAuth',
'guest' => 'App\Http\Middleware\RedirectIfAuthenticated',
];
You can try something like below. authenticate user during the routing rather then controller.
Route::get('home', array('before' => 'auth', 'do' => function()
{
// your action here
}));
Route::filter('auth',function(){
if(Auth::guest())
return Redirect::to('login');
});