I'm trying to make alive again an old project using Laravel 5.4 and Laravel Valet.
I'm facing an issue with authentication.
LoginController
public function authenticated(Request $request, User $user){
$previous_session = $user->session_id;
if ($previous_session) {
Session::getHandler()->destroy($previous_session);
}
$user = Auth::user();
$user->session_id = Session::getId();
$user->save();
Auth::login($user, true);
return redirect('testlogin');
}
Routes
Route::get('testlogin', function () {
dd(\Illuminate\Support\Facades\Auth::check());
});
In the LoginController, $user is retrieved and not null, but as soon as a redirection is made Auth::check() is false
Questions
What's wrong ? I cannot make make up my mind on this
This drove me crazy a few times as well. Most likely your 'testLogin' route is not contained within the auth middleware, which would not give you auth at the time of the route passing. If this is the case, move your 'testLogin' route inside the following:
Route::group(['middleware' => ['auth']], function () { ... HERE ... }
In the .env file, the variable SESSION_DOMAIN was not set properly and did not reflect the local domain (which had changed between now and few years ago)... Stupid error but I hope it might prevent others to do the same.
Related
I have a requirement where there is an API method (guarded by the well-known package tymon/jwt-auth) and I need to also be able to access it using the basic session based web middleware.
I don't want to repeat the route in both api.php and web.php even though that would totally work.
I tried adding both to the route but they simply don't work, like: ['auth:api', 'web']
I also tried creating a new middleware with the intention of checking both api and web like so:
class CombinedAuth
{
public function handle($request, Closure $next)
{
$web = Auth::guard('web')->user();
if ($web) {
return $next($request);
}
$api = Auth::guard('api')->user();
if ($api) {
return $next($request);
}
if(!$web && !$api) {
throw new AuthorizationException;
}
}
}
and that also doesn't work. The api middleware works fine but the web middleware doesn't and it always signs me out and redirects to the login page.
So Is there a neat way of protecting a route with api and web middlewares at the same time in Laravel 5.8?
You can use 'auth:api,web' to check for multiple guards.
Using multiple can middleware calls in Laravel 9 route;
<?php
Route::get('/', function () {
return view('money');
})
->middleware([
'can:manage,App\Models\Payment',
'can:manage,App\Models\Withdraw',
]);
?>
I'm writing a server based solution. In database there are many users with different permissions and I have to check if they have permission to access module they are trying to.
In every Controller I have included something like:
protected $module = "moduleName";
I tried to solve it like:
function __construct()
{
$perm = session()->get('perm');
if (!isset($perm[$this->module]) || !$perm[$this->module]) {
Session::flash('message_error', "<span class='glyphicon glyphicon-warning-sign'></span> Access denined!");
return back();
}
}
It shows the message but it still displays the page not redirects back.
As you see I'm reading permissions from session and modules name is saved in controller so I don't think this could be solved by middleware unless I'm making middleware for each module (I'm talking about 30 modules).
Thanks for taking the time to read this
Middleware actually solved this.
Route:
Route::group(['middleware' => 'module:moduleName'], function () {
// Routes...
});
Custom middleware:
public function handle($request, Closure $next, $module)
{
$perm = session()->get('perm');
if (!isset($perm[$module]) || !$perm[$module]) {
Session::flash('message_error', "<span class='glyphicon glyphicon-warning-sign'></span> Access denined!");
return redirect()->back();
}
return $next($request);
}
Also I'll mention that Route groups can be nested. So you can wrap multiple groups with something like auth middleware as well
There is a very easy fix to your code, you forgot the define the redirect, so instead of using
return back();
use
return redirect()->back();
This will do the redirect.
There is also a mistake in your reasoning, you could and probably should use middleware.
Middleware does have access to the user, session and can be passed parameters. These are the necessary requirements for your system.
You can also assign middleware on a controller basis.
The laravel application url will be something like app.laravel.com\{clientName}. All the routes will be following the client_name, for example app.laravel.com\{clientName}\home, app.laravel.com\{clientName}\profile. Will load/ render the application depends on the clientName.
routes/web.php
Route::group(['prefix' => '{clientName}', 'middleware' => 'appclient'], function () {
Route::get('/', 'ClientController#index');
Route::post('login', 'Auth\LoginController#login');
Route::post('logout', 'Auth\LoginController#logout');
Route::get('home', 'HomeController#index');
});
In the appclient middleware
public function handle($request, Closure $next) {
$clientName = explode('/', $request->path())[0];
$client = Client::where('clientName', $clientName)->first();
if(!isset($client->id)) {
abort(404);
}
Config::set('session.path', "/$clientName");
return $next($request);
}
What I'm trying to achieve is set the session based on the clientName directory. When I login I'm getting TokenMismatchException.
First question
Can I store the session based on url with directory like app.laravel.com\{clientName} ?
Second Question
I saw there is a setting session.path, what above I tried is to use that approach. If that is possible, how can I fixed this issue? Is it a good idea to updating the session path in the middleware?
Appreciate any feed back or other approaches
UPDATE
Using Redis as session driver
In my further investigation the request session token every time generates new one
What I did is updated the session.path & session.cookie dynamically.
Config::set('session.path', "$clientName");
Config::set('session.cookie', $clientName.'_laravel_session');
This is currently working for me.
I have my auth doing this on login.
if (Auth::attempt($userdata)) {
dd(Auth::user()); //this shows the user just fine,
//which proves that the auth driver is working.
return redirect()->intended('dashboard');
}
However, after redirecting to the dashboard. It appears the auth isn't persisted. If I do dd(Auth::user()) or even just Auth::check() it returns null.
Here's the route:
Route::group(['middleware' => ['web']], function () {
Route::get('test',function(){
dd(Auth::user()); //returns null
echo Auth::user()->name; // returns Trying to get property of non-object
});
});
What am I doing wrong?
The weird thing about this is that last night it was working. It kinda just magically stopped working.
The solution to this is not an obvious one, specially coming from older versions of laravel.
Thanks to this link.
Auth Session killed in Laravel 5.2
I was able to solve it, so I'll post the answer to help others who encounter the same issue.
Originally I just had this in my routes.
Route::post('app/login', 'Auth\AuthController#doLogin');
Route::group(['middleware' => ['web','auth']], function () {
Route::get('test',function(){
dd(Auth::user());// was always returning null
});
});
But, to get the login to persist, I had to do this
Route::group(['middleware' =>[ 'web']], function () {
Route::post('app/login', 'Auth\AuthController#doLogin');
});
Route::group(['middleware' => ['web','auth']], function () {
Route::get('test',function(){
echo Auth::user()->name;
});
});
Apparently any route thats going to call or register a session needs to employ the 'web' middleware.
Just add the "auth" middleware to your "test" route and try accessing it while logged in. It shouldn't give you any errors that way. If you try to access it without logging in, it should redirect you to whatever route is defined in the "auth" middleware.
By using "auth" middleware, you are basically ensuring that Auth::user() will always return a proper User instance.
Now, if this works then you can be sure that Laravel Auth is indeed persisting the user and the issue is somewhere else in your code.
I haven't noticed any issues with the Auth class in Laravel.
I already looking for similar issues but didn't help me.
Auth::check always return false , Auth::guest always return true, auth middleware work correct(lets request to continue if user is logged in and redirect user to login page if user is not logged in). whats wrong?
EDIT:
I understood it occurs in provider boot method , so the question would be : how to check user login status in a provider boot method?
this is my provider boot method that share a menu in all views:
public function boot(MenuController $menu_controller)
{
//dd(\Auth::check()) DOES NOT WORK HERE
$nav_menu = $menu_controller::roots()->get();
view()->share('nav_menu',$menus);
}
Auth::check() is using session to check if a User is autheticated.
In Laravel the session is initialized via middleware, and all the middlewares execute after the service providers boot phase
So, in your service provider you can't access the session: it has not been initialized yet
The solution would be to check for authentication and do your work in a middleware, and let this middleware execute after this:
\Illuminate\Session\Middleware\StartSession::class
That is the middelware that starts the session.
Another solution would be to use a callback with a view composer in the service provider:
public function boot()
{
//compose all the views....
view()->composer('*', function ($view)
{
//works here
$check = \Auth::check();
//other code...
});
}
The callback will be executed only when the view is actually being composed, so middlewares will be already executed and session will be available
i have the same issue, and i solved it
here's how i solved it
in my service provider
`
public function boot()
{
view()->composer('partial.navbar', function($view) {
$view->with('variabelToNavbar', $this->getVariable());
});
}
private function getVariable()
{
if(\Auth::check()) {
//some code u want
}
}
'
so the trick is to check auth with the function inside servide provider..
its not neat but it work for me