Laravel Middleware Auth for API - php

I am currently developing and application that has an API which I want to be accessible through middleware that will check if the user is authenticated using either Laravel's default Auth middleware and Tymone's JWT.Auth token based middleware so requests can be authenticated either of the ways.
I can work out how to have one or the other but not both, how could I do this? I'm thinking I need to create a custom middleware that uses these existing middlewares?
I am using Laravel 5.1
Thanks

Turns out I did need to make my own middleware which was easier than I thought:
<?php
namespace App\Http\Middleware;
use Auth;
use JWTAuth;
use Closure;
class APIMiddleware {
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next) {
try {
$jwt = JWTAuth::parseToken()->authenticate();
} catch (\Tymon\JWTAuth\Exceptions\JWTException $e) {
$jwt = false;
}
if (Auth::check() || $jwt) {
return $next($request);
} else {
return response('Unauthorized.', 401);
}
}
}
Then I use this middleware on my api route group like so after registering in the kernel:
Route::group(['prefix' => 'api', 'middleware' => ['api.auth']], function() {

I think you can use Route::group in your routes.php file and define the middlewares you want to use in an array.
Route::group(['middleware' => ['auth', 'someOtherMiddleware']], function()
{
Route::get('api/somethinglist', function(){
return App\Something::all();
});
});
If I'm not mistaken all routes defined within that route group is checked against the middleware(s) you specify in the array.

Related

Laravel, first user is only user

I am building a Laravel site for personal use and I would like to make the first user to register on the site be the only user. So with a fresh Laravel install with the ui installed, migration sorted and no users registered, I would like the register route to be reachable. But if there is a registered user, block the register route and only allow the login route to be reachable.
I could do something like this in the web.php
Route:get('/register', function () {...})->auth();
But I would have to do that after I first create a user. I'd rather do it in a more controllable fashion.
Edit
I don't doubt that #yves-kipondo's answer is the more correct option if I were to create this for someone else.
The solution I went with is a simple one. In my register controller I just add a check in the constructor, if there already is a user return a 404.
public function __construct() {
if (!User::all()) {
$this->middleware('guest');
} else {
abort(404);
}
}
You can create a Middleware which will be register on the register route
<?php
namespace App\Http\Middleware;
use Closure;
class RegisterOnce
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if (User::count() !== 0) {
// you can redirect wherever you want
return redirect('home');
}
return $next($request);
}
}
After that you can register the middleware in the app/Http/Kernel.php by adding this line after all registered routes middleware like this
protected $routeMiddleware = [
\\ ... previous registered middleware
'once' => App\Http\Middleware\RegisterOnce::class,
];
and you can customize the register route like this in the routes/web.php file
which wille replace the default set by Auth::routes();
Route::get('register', [App\Controllers\Auth\RegisterController::class, 'showRegistrationForm'])
->name('register')
->middleware('once');

Laravel ComposerServiceProvider redirect

On my app, I'm trying to make it so that if a user has a certain condition, he will ALWAYS be redirected to a certain page, no matter which route he tries to access. In this case, it's if he doesn't have a username (long story).
ComposerServiceProvider.php :
public function boot() {
View::composer('templates.default', function ($view) {
if(Auth::user()) {
if (Auth::user()->username == null || Auth::user()->username == "") {
return redirect()->route('auth.chooseUsername');
}
So I figured the place to do this would be
ComposerServiceProvider.php.
However, I'm noticing that my redirect don't work in ComposerServiceProvider.php. And laravel.log doesn't give me an error or reason why.
The if condition is being met. If I replace return redirect()->route('auth.chooseUsername'); with dd('test');, sure enough all my pages return 'test'.
Why is this happening?
Try this steps:
You can use middleware for this scenario like below:
Create middleware php artisan make:middleware CheckPoint
Inside App\Http\Middleware\CheckPoint.php File
use Closure;
class CheckPoint
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if($request->user()) {
if ($request->user()->username == null || $request->user()->username == "") {
return redirect()->route('auth.chooseUsername');
}
}
return $next($request);
}
}
2. Add the middleware inside the app\Http\kernel.php
protected $routeMiddleware = [
'checkPoint' => \App\Http\Middleware\CheckPoint::class,
];
Then you can use it inside your route file and controller like below
Route::get(...)->middleware('checkPoint');
Route::middleware('checkPoint')->group(function() {
//Group of routes
.....
});
More About Middleware
controller middleware
In App\Http\Middleware create a new middleware:
<?php
namespace App\Http\Middleware;
use Closure;
class CheckYourCondition
{
public function handle($request, Closure $next)
{
if (! $request->user()->yourCondition()) {
return redirect('your_target_routre');
}
return $next($request);
}
}
Register your middleware by adding it to protected $routeMiddleware in App\Http\Kernel.
and assing it to the 'web' middleware group in protected $middlewareGroups.
For details see
The ComposerServiceProvider has a different purpose. It is used to register View Composers.
View composers are callbacks or class methods that are called when a
view is rendered. If you have data that you want to be bound to a view
each time that view is rendered, a view composer can help you organize
that logic into a single location.
See View Composers.

How to add custom middleware inside a Route group in laravel

I have a Route group in laravel which has middleware of auth
Route::group(['middleware'=>'auth', function()
{
//Routes
});
Now these routes are only available to logged in users. I have a situation that logged in users have privileges. I have some routes that are only to be visited by logged in users AND if they have privilege of OWNER
In function I have started a session and stored privilege value.
I did something like this
Route::group(['middleware'=>'auth', function()
{
//Routes
if(session::get('privilege')
{
//Routes
}
});
This isn't working neither it's appropriate method. Can anyone tell me how add middleware inside a middleware?
There should be no logic inside your routes file(s) - these should simply define routes and nothing else. What you should do is define middleware which verifies privileges/roles your user has, you can specify parameters which are passed to the middleware like this:
Route::group(['middleware' => 'auth', function() {
Route::get('/my-route', 'Controller#method')->middleware('role:some_role');
Route::get('/my-other-route', 'Controller#otherMethod')->middleware('role:some_other_role');
});
Then in your middleware, you can access that parameter via a third argument in the handle method. With that value, you could verify the privileged/role the user has and then decide if the user should access that route:
public function handle($request, Closure $next, $role)
{
// Do something with $role
return $next($request);
}
If you're unsure about defining your own custom middleware, check out the docs here: https://laravel.com/docs/middleware
You will need to create a custom middleware called OWNER
php artisan make:middleware Owner
Will create a middleware file for you.
Then in the public function called handle u can do something like
if (Auth::user()->privilege == "OWNER") {
return $next($request);
}
return redirect('home');
So at the end your custom middleware will look something like this:
<?php
namespace App\Http\Middleware;
use Closure;
class Owner
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if (Auth::user()->privilege == "OWNER") {
return $next($request);
}
return redirect('home');
}
}
More about Laravel Middelware here

Change password Middleware not call

Hello in my project I am using the auto generated password from the admin side.And when the user try to login I am checking that user changed the password or not if password is not changes I want to redirect the user at the changepassword screen. I set changepasword middleware for it but middleware do not call the changepassword redirection Link.
changepasword middleware
use Closure;
use Auth;
class ChangePassword
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if ( Auth::check() && Auth::user()->isAutoPasswordChanged() )
{
return redirect('/change_password');
}
else
{
return redirect('/tests');
}
}
}
web.php
Route::group(['middleware' => 'auth', 'changepassword'], function () {
Route::resource('/tests', 'TestController');
Route::resource('/clients', 'ClientController');
});
Go to app\Http\Kernel.php
and add this to $routeMiddleware
'change_password' => \App\Http\Middleware\ChangePassword::class,
Then in your routes, replace the middle ware line with
Route::group(['middleware' => ['auth', 'changepassword']], function () {
And I also believe the logic written in ChangePassword is wrong...
It should be
if (!auth()->user()->isAutoPasswordChanged()) {
return redirect(route('auth.change.password.get'));
}
return $next($request);
First, please use the route() function instead of simple string... You will not have to change the url here, if you ever change the route from your web.php
Since you are already using the auth middleware, there is no need for you to do auth()->check().
Secondly, there should be a NOT in the condition. Because if the AutoPassword is NOT changed, only then redirect to the route, otherwise the use should be returned the next request and NOT redirected to /tests
Check registration of middleware app/Http/Kernel.php Doc
If you have a route middleware, compare the name provided in app/Http/Kernel.php
but my guess is:
'middleware' => 'auth', 'changepassword' should maybe changed in 'middleware' => ['auth', 'changepassword']
Debug if middleware itself is called

a middleware to be run during every HTTP request to application except one in laravel 5.1

I want to create my app ( I dont want to use laravel default login system)
I want to use a middleware to be run during every HTTP request in my application except one
in laravel 5.1 documention syas I can use Global Middleware but I want to not use middleware for just login page.
what should I do ?
this is my middleware :
<?php
namespace App\Http\Middleware;
use Closure;
class Admin
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if( ! session()->has('Login' ) )
{
return redirect('login');
}
return $next($request);
}
}
You can use routes group and assign your middleware to it:
Route::group(['middleware' => 'Admin'], function () {
// All of your routes goes here
});
// Special routes which you dont want going thorugh the this middleware goes here
Don't do anything to your middleware. you have the free to take that route outside the route group. so it becomes a standalone route. Or you can create a new route group and put only that one route in without that middleware. eg.
Route::group(['prefix' => 'v1'], function () {
Route::post('login','AuthenticationController');
});
Route::group(['prefix' => 'v1', 'middleware' => 'web'], function () {
Route::resource('deparments','AuthenticationController');
Route::resource("permission_roles","PermissionRolesController");
});
with this the middleware affect only the second route group
There are a couple of ways to tackle this, one is to address this in your middleware and exclude the route there, and two is to group all the routes you want to have covered by the middleware in your routes.php and then have the ones you want excluded outside of the grouping.
Tackling this in middleware
Just amend the handle function to include an if statement checking the URI requested
public function handle($request, Closure $next)
{
if ($request->is("route/you/want/to/exclude"))
{
return $next($request);
}
if( ! session()->has('Login' ) )
{
return redirect('login');
}
else
{
return redirect('login');
}
}
This method allows you to set the middleware up as global middleware and you can make multiple exclusions by extending the if statement with or $request->is().
Tackling this in routes
//Place all the routes you don't want protected here
Route::group(['middleware' => 'admin'], function () {
//Place all the routes you want protected in here
});

Categories