I'm using the jwt-auth package for Laravel. It's working great, but it seems that a user has to be authenticated or not.
For instance some routes do not require authentication, but if the token is present it should still authenticate the user. The parameters I display to user from API can vary based on the type of users access. So admins will get some additional parameters.
Right now it will always just throw token absent. But it should go through as normal and "IF" token is present, process it.
Not sure if I need to create a custom middleware for this.
class JWTAuthIfPresent
{
public function handle($request, Closure $next)
{
if (JWTAuth::getToken()) {
JWTAuth::parseToken()->authenticate();
}
return $next($request);
}
}
This seems to work, but not sure if there is a better way or something already in the existing package.
EDIT:
Also this will not deal with any token issues, like token= or some invalid or expired token. If set it should still process the token normally.
Ok, I was able to figure this out by simple extending the existing auth.
namespace App\Http\Middleware;
use JWTAuth;
use Closure;
use \Tymon\JWTAuth\Middleware\GetUserFromToken;
class JWTAuthIfPresent extends GetUserFromToken
{
public function handle($request, Closure $next)
{
if (JWTAuth::getToken()) {
return parent::handle($request, $next);
}
return $next($request);
}
}
Related
I'm using Laravel 5.5 and I'm trying to use Gate facade to allow admins to access resources like users. First, I define a gate in AuthServiceProvider.php like following:
Gate::define('view-users', 'App\Policies\UserPolicy#view');
Then, I write view method in Policy class like this:
public function view(Admin $admin, User $user)
{
return true;
}
And, I apply the authorization like following:
//UsersController.php
$user = User::first();
if (Gate::allows('view-users', $user)) {
$users = User::all();
return view('admin.users.list', compact('users'));
}
return abort(403);
I note that, the $user argument is useless variable and I don't need it to perform authorization.
By the way, when I use allows() method of Gate facade, it always returns false. While, when I use denies() instead, these steps work fine.
what's wrong with allows() method?!
However, corresponding to the Laravel Docs, I tested other ways to apply authorization via middleware(), Model or authorize(). But, I got the same result.
Edit:
I should note that I'm using custom guard named web_admin
Thanks for any help.
Change your policy method to this:
public function view(User $user)
{
return $user->isAdmin;
}
The first argument of the policy method is always the current authenticated user. Note that you are not required to pass the currently authenticated user to these methods. Laravel will automatically take care of passing the user into the gate Closure:
if (Gate::allows('view-users')) {
// The current user can view all users...
}
If you want to check if the current user can update a specific user your policy method would be:
public function update(User $authenticatedUser, User $beeingEditedUser)
{
return $authenticatedUser->isAdmin;
}
Then authorize like this:
if (Gate::allows('update-user', $beeingEditedUser)) {
// The current user can update the user...
}
If you're using custom guard (according to your comment), you may have 2 options:
Use forUser method:
use Illuminate\Support\Facades\Auth;
if (Gate::forUser(Auth::guard('web_admin')->user())->allows('view-users')) {
// The current user can view all users...
}
Protecting the routes, specifying the guard:
Route::middleware('auth:web_admin')->group(function () {
Route::get('/users', 'UserController#index');
});
This causes Larvel to set your default auth driver and resolve the auth user based on your custom guard.
I am trying to modify the Laravel Auth registration system in that I'd like to require that a token parameter be provided in order for the user to be able to access the registration page (ie http://website.dev/register/{tokenhere}). Below is the pertinent code:
From my routes\web.php file:
Route::get('/register/{token}', function() {
//
})->middleware('token');
From my \App\Http\Middleware\CheckToken.php file:
<?php
namespace App\Http\Middleware;
use Closure;
class CheckToken
{
public function handle($request, Closure $next)
{
if($request->token != 'test') { #just hard coding something here for testing purposes
return redirect('home');
}
return $next($request);
}
}
I also added 'token' => \App\Http\Middleware\CheckToken::class to the $routeMiddleware array in \App\Http\Kernel.php
However, I go to http://website.dev/register and I'm able to access the page, despite not providing a token parameter. I can also see that if I provide the 'test' parameter that the middleware is looking for (http://website.dev/register/test), I get a blank page.
Hoping someone can point me in the right direction. I'm quite new to MVC and Laravel. Thanks for your time!
You can just create custom route, like /register/{token} and handle this token in the controller. Maybe even set in middleware group if you want.
I am using a session separately other than the default authentication sessions. If an user try to access my secured page, he should have the session set. If anyone without that session try to access means, they will be redirected to error page. I am using Laravel 5.3
The user can view the below two pages only if the session variable named 'secured_user' is set. Otherwise they will be redirect to the error page
Route::get('/secured-page1', 'ValidationController#CheckSecuredLogin_1');
Route::get('/secured-page2', 'ValidationController#CheckSecuredLogin_2');
The best option would be a policy.
You can create certain constrains and couple it with your models. Policies are especially suitable for changing your logic later on.
See here: Create Policy
Within you PagesPolicy, you can add this function:
public function before(User $user, $ability)
{
if ($user->isSuperAdmin()) {
return true;
}
}
public function seeSecurePage(User $user)
{
// Your custom Code and session handling
if(session("secured_user")) return true;
return false;
}
and in your controller.
$user->can("seeSecurePage","Pages");
If "can" fails, it will automatically redirect to error 403.
P.S.: Another possibility are Gates
You should use Laravel Middlewares to achieve this, I think middlewares are made for the work you need:
First create a new middleware by running the artisan command:
php artisan make:middleware CheckSesison
Then the CheckSession would look like this:
<?php
namespace App\Http\Middleware;
use Closure;
class CheckSession
{
public function handle($request, Closure $next)
{
if ($session_value != 'YOUR_DESIRED_VALUE') {
return redirect('home');
}
return $next($request);
}
}
Now in your routes file you can use laravel's route middleware() method to implement it like this:
Route::get('/secured-page1', 'ValidationController#CheckSecuredLogin_1')
->middleware(CheckSession::class);
Hope this helps!
In addition to the awnser above, you could also use middleware that's used on the routes and even group them if required. It is a simple, quick and clean solution. Inside the middelware you simple check if the session you require is there and depending on the result you take any action necessary.
Laravel middleware docs
In Laravel 5, if basic auth fails for a user then the default message that is returned is an "Invalid Credentials" error string. I am trying to return a custom JSON error when this situation occurs.
I can edit the returned response in vendor/laravel/framework/src/Illuminate/Auth/SessionGuard.php
however I have not seen where you can change the behavior of this message outside of the vendor directory. Is there a way?
Looks like there were some ways to do this through Laravel 4: Laravel 4 Basic Auth custom error
Figured it out, looks like I had to create custom middleware to handle this.
Note that this solution didn't work when calling my API from my browser, only when calling it from a tool like Postman. For some reason when calling it from my browser I always got the error before seeing the basic auth prompt.
In my controller I changed the middleware to my newly created one:
$this->middleware('custom');
In Kernel I added the location for it:
protected $routeMiddleware = [
'auth.basic.once' => \App\Http\Middleware\Custom::class,
]
Then I created the middleware. I used Stateless Basic Auth since I'm creating an API:
<?php
namespace App\Http\Middleware;
use Auth;
use Closure;
use Illuminate\Http\Request as HttpRequest;
use App\Entities\CustomErrorResponse
class Custom
{
public function __construct(CustomErrorResponse $customErrorResponse) {
$this->customErrorResponse = $customErrorResponse
}
public function handle($request, Closure $next)
{
$response = Auth::onceBasic();
if (!$response) {
return $next($request);
}
return $this->customErrorResponse->send();
}
}
For some reason I have had a mind block and can't figure out what is probably a very simple fix.
I have a Laravel 5 App and am using Zizaco's Entrust package for Access Control.
I want to protect a route so am using route Protection in routes.php as follows:
Entrust::routeNeedsRole('passtypes', array('admin'), null, false);
Which works as expected, apart from when a user's session has expired or they are not logged in and try to access the route.
In this case I would want Laravel's Authentication to be checked first, and redirect to the login page; however Entrust redirects to the 403 error first; which is confusing for a user that has ability to view that page, but is told they do not have access, rather than that they are not logged in/session has expired.
I initiate the Authentication in the Controller rather than in the route:
public function __construct()
{
$this->middleware('auth');
}
So just need to know how to get the same functionality, but by having auth get checked before the route permission requirement.
Thanks
I think that Entrust::routeNeedsRole fires before controller. Can you move Entrust to middleware? You could then check in middleware if user is logged in and then check if he has required role.
It's been a while, but I had a similar problem. The only difference, my entire app had to be protected. I ended up modifying Authenticate Middleware handle method:
public function handle($request, Closure $next)
{
if ($this->auth->guest()) {
if ($request->ajax()) {
return response('Unauthorized.', 401);
} else {
/**
* This is to protect the entire app, except login form,
* to avoid loop
*/
if($request->path() != 'auth/login')
return redirect()->guest('auth/login');
}
}
return $next($request);
}
And inside Kernel.php moved Authenticate from $routeMiddleware to $middleware
Then you can protect your routes with Entrust.