Laravel 5 : How to use Auth::user()->id in route - php

I try to create a application using php Laravel framework .When i use Auth::user()->id in my route file i got error "Trying to get property of non-object" .So how to i fix it?
This is my route file
`
<?php
/*
|--------------------------------------------------------------------------
| Application Routes
|--------------------------------------------------------------------------
|
| Here is where you can register all of the routes for an application.
| It's a breeze. Simply tell Laravel the URIs it should respond to
| and give it the controller to call when that URI is requested.
|
*/
Route::get('/', 'HomeController#index');
Route::controllers([
'auth' => 'Auth\AuthController',
'password' => 'Auth\PasswordController',
]);
$common_variable=App\MyModel::where('site_id',Auth::user()->id)->count();
view()->share(compact('common_variable'));
`

If you want something to execute you should use laravel 5 middleware.
1.- php artisan make:middleware newMiddleware.
2.- Add your middleware to all routes you need by setting the middleware property.
Route::get('test', ['before' => 'newMiddleware', function(){
//
}]);
3.- Now do in a proper way what you where trying to accomplish
$user_id = Auth::user()->id()
if($user_id){
$variable = \App\Model::where('site_id', '=', $user_id)
}
return $variable
4.- Now you have your wanted value in your route function / controller, you can pass it to the view along with other data.

you have to define your route, otherwise it will not work
Route::get('/testauth', function()
{
var_dump(Auth::user());
// your code here
});
Now hit the 'testauth' route. It should be working.

You can't access the authenticated user in a route model binding because the authentication middleware has not run. Please see thus discussion thread where some workarounds are proposed.

you have to make sure your user is authenticated
$common_variable=Auth::check() ?App\MyModel::where('site_id',Auth::user()->id)->count() : 0;
when you are not authenticated Auth::user() will always return null and you are referring id on a null object which give you the error

This is how I did this. I wanted to restrict a view to an owner of the requested object, in my case an "API Key". I used Laravel's route model binding to do this.
Route::model('apikeys', 'Apikey');
Route::bind('apikeys', function($value, $route) {
return Apikey::whereSlug($value)->where('users_id', '=', Auth::user()->id)->where('approved', '=', true)->where('deleted', '=', false)->first();
});
Route::resource('apikeys', 'ApikeysController');
In this case, I'm passing in the value of the requested "slug" (i.e. the friendly url of the api key), then appending an AND'ed where clause with the authenticated user ID, approved = true, and deleted = false.

Related

Can U use the middleware the same way in the controller or route?

I'm trying to make sure that you can't just type /admin into the top bar. I made an extra column in the user table called admin and it's either 0 (normal user) or 1 (admin).
In the blade page, I'm checking:
#if (Auth::check())
#if (Auth::user()->admin == 1)
<p>Hello Admin</p>
#else
<p>Hello standard user</p>
#endif
#endif
I was asking if it's possible to either check in the route (something like this)
Route::get('/home', 'HomeController#index')->name('home')->middleware('auth')-where('admin' 1);
or in the controller (something like this)
public function __construct()
{
$this->middleware('auth')->where('admin' 1);
}
You can achieve this using a new middleware.
First create a new middleware by typing in your console:
php artisan make:middleware isAdmin
Name your middleware whatever you like, isAdmin is common here.
Next you must add the middleware to your Kernel.php located at app/Http/Kernel.php, edit the array named $routeMiddleware and add the following:
'isAdmin' => \App\Http\Middleware\IsAdmin::class,
Open your IsAdmin.php located in your middleware folder and modify the handle method like so:
{
if (Auth::user() && Auth::user()->admin == 1) {
return $next($request);
}
return redirect('/');
}
Note: the middleware will also check if a user is authenticated so could be used in place of auth for admin routes, remember to modify the return to suit your needs
Lastly, add the middleware to your route, there are a number of ways to do this.
if you are planning to use it instead of auth middleware, simple change auth to isAdmin in your routes file ->middleware('isAdmin')
Another option is to modify your routes file like so
Route::group(['middleware => 'auth'], function () {
Route::get('/home', 'HomeController#index')->name('home')->middleware('isAdmin');
}
So you don't need to apply the middlewares to each route, there are a bunch of possibilities for this here https://laravel.com/docs/7.x/middleware#assigning-middleware-to-routes

Declare same route twice but expect different behaviour according to a middleware

I started creating a REST API using the lumen framework and wanted to set up a particular behaviour for my GET /user route. Behaviour is the following:
If the request come from an authenticated user (using auth middleware), the method getAllFields from UserController is called and return all the data from the user
If it's not the case, the method get from UserController is called and return some of the data from the user
It seems logic to me to just write it like that in my web.php using a simple middleware:
<?php
$router->group(['middleware' => 'auth'], function () use ($router) {
$router->get('/user/{id}', [
'uses' => 'UserController#getAllFields'
]);
});
$router->get('/user/{id}', [
'uses' => 'UserController#get'
]);
But for some reason, even if the middleware is correct, I always get the response of the second route declaration (that call get()). I precise that if I remove the second route declaration, the one in the middleware work as expected.
Have someone an idea how I can achieve something similar that work?
Router will check if your request matches to any declared route. Middleware will run AFTER that match, so You cannot just return to router and try to find another match.
To fallow Laravel and Routes pattern - You should have single route that will point to method inside controller. Then inside that You can check if user is logged or not and execute getAllFields() from that controller. It will be not much to rewrite since You are currently using UserController in both routes anyway.
web.php
$router->get('/user/{id}', 'UserController#get');
UserController.php
public function get()
{
return auth()->check() ? YourMethodForLogged() : YourMethodForNotLogged();
}
Or if there is not much logic You can keep this in single method.
Also it is good idea to fallow Laravels REST standards (so use show instead of get, "users" instead of "user" etc - read more https://laravel.com/docs/7.x/controllers)
web.php
$router->get('/users/{user}', 'UserController#show');
UserController.php
public function show(User $user)
{
if (auth()->check()) {
//
} else {
//
}
}
To summary - for your needs use Auth inside controller instead of middleware.
To check if user is logged You can use Facade Auth::check() or helper auth()->check(), or opposite Auth::guest() or auth()->guest().
If you are actually using Lumen instead of full Laravel then there is not auth helper by default (You can make own or use package like lumen-helpers) or just keep it simple and use just Facades instead (if You have then enabled in Lumen).
Read more https://laravel.com/docs/7.x/authentication and https://lumen.laravel.com/docs/7.x/authentication
This pattern is against the idea of Laravel's routing. Each route should be defined once.
You can define your route without auth middleware enabled and then define your logic in the controller.

Problem in my test function trying to access group of routes

What I'm trying to test is to access some routes but these routes are in laratrust role middleware this role is the auth user must be super admin to go in this routes my problem is I don't know how to write this function.
I tried to make the user super admin in the test function like this
public function Test()
{
$user = factory(User::class)->create();
$user->attachRole('superadministrator');
$this->actingAs($user, 'api');
$response = $this->json('GET', 'api/users');
$response->assertStatus(200);
}
but it didn't work even I checked the data base this user is superadministrator and the test give like I'm not super admin
This is my api routes:
Route::group(['middleware' => ['auth:api', 'role:superadministrator']],
function()
{
Route::apiResource('users', 'UserController');
}
This is my index function in UserController:
public function index()
{
return Response()->json(User::all, 200);
}
What I'm expect is a function can access this route because there is more routes in this group and the rest of the tests depends on this function
I've never used Laratrust, but after a quick look at its source code, it looks like the issue is that you need to specify the api guard on your role middleware check. Add ,guard:api to your role middleware:
Route::group(['middleware' => ['auth:api', 'role:superadministrator,guard:api']], function() {
Route::apiResource('users', 'UserController');
}
In the role middleware check, if you don't specify the guard, it will use the default guard defined in your auth config (which is web if you haven't changed it). So, the middleware will be looking for the user from the web auth guard, which doesn't exist.
The good news is, your test worked! It found a bug in your route definition.

Multiple middleware not working on laravel

I have a route resource group that can only be accessible by one of 2 middleware rules. I have registered them both and they both work independently if I test them both out alone, but when I have them together they don't work
I have tried running them both as either an "or" statement (which means the middleware works as intended) but this means that anyone not logged in can also access the routes for some reason. If I use a comma to separate the middleware, it's blocked for everyone. I know both middleware works ok as they do work if I try them independently. I am using the below code
Route::group(['middleware' => ['IsAdmin' or 'IsPatreon']], function(){
Route::resource('patreon', 'patreonGalleryController', ['names'=>[
'index'=>'patreonGallery.index',
'create'=>'patreonGallery.create',
'store'=>'patreonGallery.store',
'edit'=>'patreonGallery.edit',
'show'=>'patreonGallery.show',
'destroy'=>'patreonGallery.destroy',
]]);
});
How can I set it so that only either admin or patreon uses can see the paths?
Two middlewares are working separately.
IsAdmin is checking that user is admin
IsPatreon is checking that user is patreon...
You cannot merge these 2 middlewares by OR Operator
Probably you need to create new middelware, something like
IsAdminOrPatreon and do you checks inside of that middleware and assing that middleware to your Group..
Or you can try with middleware parameters, for example
Route::group(['middleware' => ['checkRoles:admin,patreon']], function(){
Route::resource('patreon', 'patreonGalleryController', ['names'=>[
'index'=>'patreonGallery.index',
'create'=>'patreonGallery.create',
'store'=>'patreonGallery.store',
'edit'=>'patreonGallery.edit',
'show'=>'patreonGallery.show',
'destroy'=>'patreonGallery.destroy',
]]);
});
And in you checkRoles middleware get the admin and patreaon roles like this:
public function handle($request, Closure $next) {
// will contain ['role1', 'role2']
$allowedRoles = array_slice(func_get_args(), 2);
// here you can loop and check your roles
}
Note! If you pass 'checkRoles:admin,patreon' you will get
array(admin,patreon)
If you pass 'checkRoles:admin' you will get
array(admin)
you can't use or condition inside middleware array. middleware array always return and condition. you can specify the user role inside your middleware.
gist sample role middleware
https://gist.github.com/ivanhoe011/931417be3e36b3f06e994bfe5cd004f9
You do something like this in your controller.
public function __construct()
{
return ($this->middleware('IsAdmin')) || $this->middleware('IsPatreon');
}
Each route on this controller will be authenticated by any one of middleware.

Laravel Routing to Wrong View

I'm working with Laravel 4.2. I have an app that's routing to the wrong view, although the URL is correct. On a button click, it's supposed to route to users.create (UsersController#create), but is instead routing to UsersController#show. The resolved URL is correct, though, and the DOM element has the correct URL listed. Can anyone help me out?
Here is my Routes file:
// Home page
Route::get('/', 'BaseController#index');
// Define User model to pass through routes
Route::model('user', 'User');
// Create custom route for editing a user
Route::get('users/edit/{user}',
array('as' => 'users.edit', 'uses' => 'UsersController#edit'));
// Create custom route for showing a user
Route::get('users/{user}',
['as' => 'users.show', 'uses' => 'UsersController#show']);
// Remaining routes
Route::resource('users', 'UsersController',
array('except' => array('edit', 'show')));
Here is my UsersController with the two functions in question:
class UsersController extends \BaseController {
protected $user;
public function create()
{
return View::make('users/create');
}
public function show($user)
{
return View::make('users/show', ['user' => $user]);
}}
And here are the relevant results from php artisan routes:
GET:HEAD users/{user} users.show UsersController#show
GET:HEAD users/create users.create UsersController#create
Thanks for your help!
Edit:
The answer to the problem was to simply re-order the routes so that the resource is defined first. I was aware that Laravel grabs the first route that matches a URI, but I still don't understand why a route that isn't passed a user object would select a route defined as users/{user}. Furthermore, I was accessing the route via link_to_route(), that is to say, by name. Why would Laravel pick a different route from the one I explicitly named?
I suppose these questions are beyond the scope of the initial question, but I would greatly appreciate further explanation from someone. Problem solved!
The first thing that jumps out at me is there is no route for "create". There is the "restful" controller, but maybe you want to just try putting the route in. I'm slightly uncomfortable using restful routes when serving html. In the project i'm working on i've been trying to preserve those for data/json transmission, in order to support outside api action.
I think your routes setup recognizes create as {user} in user/{user}, thus redirect to user/show/create as your "custom route for showing a user" setup.
You may have to avoid getting string variable right after users/ route.

Categories