Auth::logout() prioritizing above all code - laravel

I'm working on a project wich needs an online status on the user so i just added an on auth.logout event to listen for logouts and put the status to false for offline. In the event when logged the $event->user value is null. So I tried checking the function that calls Auth::logout() in my project and for some reason the code is being triggered before all the other code. Any one has any idea ?
Here it still has the User Model data.
protected function logout()
{
$user = Auth::user();
$user->online = 0;
$user->save()
//Auth::logout();
return redirect()->intended(route('page.login'));
}
But here the $user = null
protected function logout()
{
$user = Auth::user(); //$user = null
$user->online = 0;
$user->save();
Auth::logout(); //Is this taking priority over all code somehow ?
return redirect()->intended(route('page.login'));
}

There is absolutely no way that code is jumping precedence. If that was possible, software development would be an impossible feat of coincidence and magic -- more so than it already is.
It's much more likely that that code is executing twice. Try setting up the controller logic so that it can function if $user is null. I would bet money that logout() is running multiple times.
protected function logout()
{
$user = Auth::user();
if ($user)
{
$user->online = 0;
$user->save();
Auth::logout();
}
return redirect()->intended(route('page.login'));
}

Related

If Statement not working properly in Laravel Controller

I have a simple If Statement in my controller that is not triggering properly.
I have the following route:
Route::resource ('/my-health-hub', 'MyHealthHubController');
I have the following in my controller:
public function index(Request $request)
{
$test = Auth::check();
if ($test = false){
return redirect('/login');
} else {
$providers = $request->user()->providers()->get();
return view ('my-health-hub', compact('providers'));
}
}
When a user is logged in, the second part of the If Statement is triggered properly. However, when logged out, the If Statement still tries to trigger the second part of the If Statement. I did dd($test) to verify the value was false when logged out and it was. So, the second part of the statement should not be triggering when user is logged out.
When you try to make a logic comparison you use two assignment operator for compare
in your case you use one assignment operator = so it will return true in first case all the time
so all you need to fix it to add == instead of =
public function index(Request $request)
{
$test = Auth::check();
if ($test == false){
return redirect('/login');
} else {
$providers = $request->user()->providers()->get();
return view ('my-health-hub', compact('providers'));
}
}
We can remove else block completely. It can be written as below (some code optimizations).
public function index(Request $request)
{
$test = Auth::check();
if ($test){
$providers = $request->user()->providers()->get();
return view ('my-health-hub', compact('providers'));
}
return redirect('/login');
}

How to add expiry date condition to login function in laravel 5.2

In laravel 5.2, i want to add the condition so that only users where their expiry date is greater than today's date to login.
protected function getCredentials(Request $request)
{
return ['email' => $request->{$this->loginUsername()}, 'password' => $request->password];
}
The code does not accept adding:
'expires' => gte(Carbon::now())
Any help is appreciated
I don't think this is possible, even in Laravel 5.5. Taking a look at the retrieveByCredentials method in Illuminate\Auth\EloquentUserProvider which is used to get the user from the database, you can see that the query passes simple key/value combinations to the where method on the $query object, which equate to where key = value. This is from 5.5:
public function retrieveByCredentials(array $credentials)
{
if (empty($credentials) ||
(count($credentials) === 1 &&
array_key_exists('password', $credentials))) {
return;
}
// First we will add each credential element to the query as a where clause.
// Then we can execute the query and, if we found a user, return it in a
// Eloquent User "model" that will be utilized by the Guard instances.
$query = $this->createModel()->newQuery();
foreach ($credentials as $key => $value) {
if (! Str::contains($key, 'password')) {
$query->where($key, $value);
}
}
return $query->first();
}
To achieve what you are after I would recommend doing this check after the user has logged in, in your controller for instance:
// Imagine this is the controller method where you're dealing with user logins
public function login(array $credentials)
{
if (! auth()->attempt($credentials)) {
// Handle what happens if the users credentials are incorrect.
}
$user = auth()->user();
if (Carbon::now()->gte($user->expires)) {
// User's account has expired, lets log them out.
auth()->logout();
// Return a redirect with a message or something...
}
// Handle a successful login.
}
I'm not sure if the auth() helper is available in 5.2, but you should be able to use the Auth facade to do the same thing, e.g. Auth::attempt(...).

Laravel issue with loginUsingId (Manual Authentication)

I am trying to implement a single signon on multiple domains. The concept is pretty simple i.e to send unique user tokens and then verify these tokens to find the user and then log him in.
Now after verifying the token and then grabbing the user, i do something like this
$loggedInUser = Auth::loginUsingId($user->id, true);
Now i have a custom middleware where it first checks for a logged in user, i.e
Auth::Check()
The above works fine for the first time. But on refresh Auth::check() is not validated. I have also tried using all different session drivers but still doesn't work.
I used a similar code on laravel 5.2, and it did work. But on laravel 5.3 its not validating on persistent requests.
Edit: Let me show you my Code
I have not modified AuthServiceProvider or any other guard. I do have the user model inside a directory but i have modified the path in auth.php.
Here is the route that domain1 points to:
http://domain2.com/{{$role}}/{{$route}}/singlesignon/{{$token}}
This is then picked up by verifySingleSignOn method inside the loginController which takes in the role, route that the user came in from other domain and the token. The user is then redirected to the same routes, but on domain2. Here i can successfully recieve the user id before manually logging in.
public function verifySingleSignOn($role, $route, $token)
{
// Fetch Single Signon
$userRepository = new UserRepository();
$user = $userRepository->checkForSingleSignOnToken($token, ['id']);
// Check if Token Exists
if (isset($user->id) && is_int($user->id) && $user->id != 0) {
// Manually Logging a user (Here is successfully recieve the user id)
$loggedInUser = Auth::loginUsingId($user->id);
if (!$loggedInUser) {
// If User not logged in, then Throw exception
throw new Exception('Single SignOn: User Cannot be Signed In');
}
$redirectTo = $role . '/' . $route;
return redirect($redirectTo);
} else {
return Auth::logout();
}
}
Then i have this GlobalAdminAuth middleware
// Check if logged in
if( Auth::Check() ){
$user = Auth::User();
// Check if user is active and is a globaladmin
if( !$user->isGlobalAdmin() || !$user->isActive() ){
return redirect()->guest('login');
}
}else{
return redirect()->guest('login');
}
return $next($request);
Now the first time everything works fine and the user moves through the middleware successfully . but the second time the else statement is triggered.
Edit: Code for checkForSingleSignOnToken
public function checkForSingleSignOnToken($token, $columns = array('*'))
{
return User::where('single_signon', $token)->first($columns);
}
try
Auth::login($user);
instead of
Auth::loginUsingId($user->id, true);
Cookies are restricted domain-wise. Your application on domain1.com wont be able to grab cookies set by domain2.com.
You should be customizing the guard to use some other mechanism than cookies. Maybe use a token in the query parameters.
add this to your protected $middleware array in app\Http\Kernel.php
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class
I think it has to do with an update in the framework
no using auth:check in middleware
using request->user() or auth::user()
Please review bellow code structure, i had made manual authentication
in laravel 5.0.
routes.php
Route::get('login_user_by_id/{id?}', ['as' => 'login_user_by_id', 'uses' => 'UsersController#login_user_by_id']);
Route::post('user_login_post_for_admin',['as'=>'user_login_post_for_admin','uses'=>'LoginController#user_login_post_for_admin']);
Route::get('user_logout', ['as' => 'user_logout', 'uses' => 'UsersController#user_logout']);
LoginController.php
public function user_login_post_for_admin(){
$this->set_email($_POST['email']);
$this->set_password($_POST['password']);
$this->set_login_requested_role(['Admin','Moderator']);
return $this->user_login_post();
}
public function user_login_post(){
$User = new User();
if(isset($this->email) && !empty($this->email)){
$User->set_email(trim($this->email));
$User->set_password(Hash::make(trim($this->password)));
$user_login_data = $User->check_email_password_for_login();
if(isset($user_login_data) && !empty($user_login_data)){
if (Hash::check(trim($this->password), $user_login_data[0]->password)) {
$response['user_id']=$user_login_data[0]->id;
$response['name']=$user_login_data[0]->name;
$response['surname']=$user_login_data[0]->surname;
$response['profile_picture']=$user_login_data[0]->profile_picture;
$response['SUCCESS']='True';
$response['MESSAGE']='Login Success.';
return Redirect::route('login_user_by_id',[$user_login_data[0]->id]);
}else{
Session::put('SUCCESS','FALSE');
Session::put('MESSAGE', 'Invalid Credential.');
return redirect()->back();
}
}else{
Session::put('SUCCESS','FALSE');
Session::put('MESSAGE', 'Invalid Credential.');
return redirect()->back();
}
}else{
Session::put('SUCCESS','FALSE');
Session::put('MESSAGE', 'Invalid Credential.');
return redirect()->back();
}
}
UsersController.php
public function login_user_by_id($id=''){
if(isset($_GET['id'])&&!empty($_GET['id'])){
$id = $_GET['id'];
}
$User = new User();
$Log=new Log();
$user_for_auth = $User->find($id);
Auth::login($user_for_auth, true);
$User->id=AUTH::user()->id;
$auth_user_role=$User->auth_user_role();
$rl_title=$auth_user_role[0]->rl_title;
return Redirect::route('admin_home');
}
public function user_logout(User $user){
$User=new User();
$login_user_id = AUTH::user()->id;
$User->id=AUTH::user()->id;
$auth_user_role=$User->auth_user_role();
$login_user_role=$auth_user_role[0]->rl_title;
$response['user_id']=$login_user_id;
$response['SUCCESS']='TRUE';
$response['MESSAGE']='Successfully Logout.';
Auth::logout();
return Redirect::route('admin_login');
}

Laravel 5 Authentication: Call to a member function getEmailForPasswordReset() on null

I'm using the authentication included with laravel 5.2
I have a problem at reset password form.
When I submit email, it returns this error:
Call to a member function getEmailForPasswordReset() on null
I found this cause by the following code:
$user->getEmailForPasswordReset()
the $user is null
In addition, I try to change Illuminate\Auth\Passwords\PasswordBroker at function emailResetLink
return $this->mailer->send($view, compact('token', 'user'), function ($m) use ($user, $token, $callback) {
$m->to($user->getEmailForPasswordReset());
if (! is_null($callback)) {
call_user_func($callback, $m, $user, $token);
}
});
I change: compact('token', 'user') -> ['token'=>$token, 'user2'=>$user]
And $user->getEmailForPasswordReset() -> $user2->getEmailForPasswordReset()
It works well!
Can you help me figure out what I did wrong?
Thanks.
The problem is definitely not in laravel files, so stop looking there and messing with the code, because you risk breaking more stuff than you will fix and also it will be overwritten once you do composer update.
The $user is null because the system cannot find the user you want to send a password reset link to. It would be more helpful to see your controller that implements the password resetting (submitting). Laravel comes with a pretty good starting point and you should not overengineer it unless needed: https://laravel.com/docs/5.2/authentication#resetting-routing
So the method for sending reset links would look something like this:
public function postEmail(Request $request)
{
$this->validate($request, ['email' => 'required|email']);
$response = Password::sendResetLink($request->only('email'), function (Message $message) {
$message->subject($this->getEmailSubject());
});
switch ($response) {
case Password::RESET_LINK_SENT:
return redirect()->back()->with('message', 'Password reset link sent');
case Password::INVALID_USER:
return redirect()->back()->with('message', 'User not found');
}
}
As you see there's no User objects involved for you to handle.

Authorization Using Form Requests in Laravel

Not sure what I am doing wrong here but I am having trouble getting the $id of the post to pass to the form request when checking to see if the person editing owns the post. "Job" would be a job posting. Below is the logic in the JobsRequest.
public function authorize()
{
$job=Job::find($this->id);
if($job->user_id == Auth::user()->id){
return true;
}else{
return false;
}
The above keeps returning as false. The update method in the controller is below
public function update(JobsRequest $request, $id)
{
$job=Job::find($id);
$job_data=$request->all();
$job->update($job_data);
return redirect('/jobs/'.$job->id.'/edit');
}
To grab the id within the FormRequest object, you'd need to use the following...
$id = $this->route('id');
Go to the AuthServiceProvider.php and write
$gate->define('show-product',function($user,$product){
return $user->id==$product->customer_id;
});
Then write your controller
$product= Product::find($id);
Auth::loginUsingId(3);
//Auth::logout();
if(Gate::denies('update',$product)){
App::abort('404','Product Not Found');
}
// $this->authorize('update',$product);
return $product->name;
I think It's working perfectly
Try this, which gets the id from the route parameter.
public function authorize(){
$job_id = $this->route('id');
$job=Job::find($job_id);
$user = $this->user();
if($job->user_id == $user->id) return true;
return false;
}
Thanks for pointing me in the right direction. I got this straight from the docs.. This worked for me.
$jobId = $this->route('jobs');
return Job::where('id', $jobId)
->where('user_id', Auth::id())->exists();

Resources