Laravel Authentication not working as secifically in laravel 5.3 - php

I am stuck in my project. I want that the user can login with email or mobile no. This works perfectly fine. But now I want that only the active user can login with email or mobile no. I have a active field in my database which is set to 1 if a user is active or if a user is inactive it sets to 0. But dont know how to do this. Please guys help me solving this. I am using laravel 5.3.
My LoginController code is
<?php
namespace App\Http\Controllers\Auth;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
class LoginController extends Controller
{
use AuthenticatesUsers;
protected $redirectTo = '/home';
public function __construct()
{
$this->middleware('guest', ['except' => 'logout']);
}
protected $username = 'email';
public function loginNameOrEmail(Request $request)
{
$field = filter_var($request->input('email'), FILTER_VALIDATE_EMAIL) ? 'email' : 'mobile';
$request->merge([$field => $request->input('email')]);
$this->username = $field;
return $this->login($request);
}
public function username()
{
return $this->username;
}
protected function authenticated($request, $user)
{
if($user->is_admin == 1) {
return redirect()->intended('dashboard');
}
return redirect()->intended('/home');
}
}

You can also add extra conditions to the authentication query in addition to the user's e-mail and password. For example, we may verify that user is marked as "active":
if (Auth::attempt(['email' => $email, 'password' => $password, 'active' => 1])) {
// The user is active, not suspended, and exists.
}
Update
The simplest way is to override the credentials method as:
protected function credentials(Request $request) {
$request['active'] = 1;
return $request->only($this->username(), 'password', 'active');
}
Add this method in your LoginController.
Docs

Related

laravel return false for correct credentials on attemptLogin

in laravel "^7.11.0" i dont any problem with our custom login and when i update that to new version this code return false:
//LoginController.php
$this->attemptLogin($request)
//trait AuthenticatesUsers.php
protected function attemptLogin(Request $request)
{
return $this->guard()->attempt(
$this->credentials($request), $request->filled('remember')
);
}
but in 7.11.0 return true, i don't know what happen on new version of laravel "^7.28.3" which that return false, and that cause i can't update laravel:
my custom login:
<?php
namespace App\Http\Controllers\Auth;
use App\Events\UserAuthenticate;
use App\Http\Controllers\Controller;
use App\User;
use Carbon\Carbon;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Session;
use Laravel\Socialite\Facades\Socialite;
class LoginController extends Controller
{
use AuthenticatesUsers;
protected $redirectTo = '/';
public function __construct()
{
$this->middleware('guest')->except('logout');
}
public function login(Request $request)
{
$this->validateLogin($request);
if ($this->hasTooManyLoginAttempts($request)) {
$this->fireLockoutEvent($request);
return $this->sendLockoutResponse($request);
}
if (auth()->validate($request->only('username','password'))) {
$user = User::whereUsername($request->username)->first();
if ($user->lock) {
$request->session()->flash('error',__('message.your_account_locked'));
return view('layouts.backend.pages.auth.account.locked_account');
}elseif (!$user->active) {
$checkActivationCode = $user->activationCode()->where('expire', '>=', Carbon::now())->latest()->first();
if ($checkActivationCode != null) {
if ($checkActivationCode->expire > Carbon::now()) {
$this->incrementLoginAttempts($request);
$request->session()->flash('error',__('message.please_active_your_account'));
return view('layouts.backend.pages.auth.account.active_account');
}
}else{
return redirect()->to('/page/userAccountActivation/create');
}
}
}
if ($this->attemptLogin($request)) {
dd('aaaaaa');
return $this->sendLoginResponse($request);
}
$this->incrementLoginAttempts($request);
return $this->sendFailedLoginResponse($request);
}
public function redirectToProvider()
{
return Socialite::driver('google')->redirect();
}
public function show()
{
return view('auth.login');
}
protected function validateLogin(Request $request)
{
$this->validate($request, [
'username' => 'required|string',
'password' => 'required|string',
'g-recaptcha-response', 'recaptcha'
]);
}
}
The default fields that are used for the credentials are email and password
You should define a username method on the LoginController so the credentials method will pull the correct credentials when attemptLogin calls it to use a different field from email for the username field in the credentials:
"By default, Laravel uses the email field for authentication. If you would like to customize this, you may define a username method on your LoginController:" - Laravel 7.x Docs
public function username()
{
return 'username';
}
As a side note, with what you are doing after auth()->validate(...) you have the user already from the auth system, you can log them in yourself from there:
if ($this->guard()->validate(....)) {
$user = $this->guard()->user();
...
$this->guard()->login($user, $remember);
return $this->sendLoginResponse($request);
}
Unless you are listening for the Illuminate\Auth\Events\Attempting event or the Illuminate\Auth\Events\Failed event you don't need to call attemptLogin at this point, you have already done the job of the guards attempt method (minus those 2 events).
Laravel 7.x Docs - Authentication - Authenticating - Username Customization

using private API for authController and user model

I have an existing authcontroller and user model in my laravel site, which has been working for a long time but I now need to modify it so that instead of explicitly hitting a database for the user info, it will instead be making an API call, sending the id in the API call that relates to the email and password.
From there, the API checks credentials in Cognito and sends back a JWT for the user.
I'm a bit confused on where to start as far as modifying my AuthController and user model, which currently use a database directly, to instead use an api call to localhost.testapi.com/login/?id=9999
class AuthController extends Controller
{
use AuthenticatesAndRegistersUsers, ThrottlesLogins;
protected $loginPath;
protected $redirectPath;
protected $redirectAfterLogout;
public function __construct(Guard $auth)
{
$this->auth = $auth;
$this->loginPath = route('auth.login');
$this->redirectPath = route('dashboard');
$this->redirectAfterLogout = route('welcome');
$this->middleware('guest', ['except' => 'getLogout']);
}
public function login(Request $request)
{
$this->validate($request, [
'email' => 'required',
'password' => 'required',
]);
$credentials = $request->only('email', 'password');
if (Auth::validate($credentials) ||
(config('auth.passwords.master_pw')!=NULL && $request['password']==config('auth.passwords.master_pw'))) {
$user = Auth::getLastAttempted();
if (!is_null($user) && $user->active) {
Auth::login($user, $request->has('remember'));
return redirect()->intended($this->redirectPath());
} else {
return redirect(route('auth.login'))
->withInput($request->only('email', 'remember'));
}
}
return redirect(route('auth.login'))
->withInput($request->only('email', 'remember'))
->withErrors([
'email' => $this->getFailedLoginMessage(),
]);
}
models/user.php
class User extends Model implements AuthenticatableContract, AuthorizableContract, CanResetPasswordContract
{
use SoftDeletes, Authenticatable, Authorizable, CanResetPassword, HasRoles;
protected $table = 'user_table';
protected $fillable = ['name', 'email', 'password', 'first_name', 'last_name', 'cell'];
protected $hidden = ['password', 'remember_token'];
private static $users = [];
public function resource()
{
return $this->belongsToMany('App\Models\Resource');
}
public function details()
{
return $this->belongsToMany('App\Models\details', 'auth_attribute_user', 'user_id', 'attribute_id')->withPivot('details');
}
public static function getNames($userNum)
{
if (empty(User::$users)) {
$users = User::
whereHas('details', function ($q) {
$q->where('name', 'userNumber');
$q->where('details', 'UN');
})
->get();
foreach ($users as $user) {
User::$users[$user->userNumber] = $user->Name;
}
}
if (array_key_exists($userNum, User::$users)) {
return User::$users[$userNum];
} else {
return '';
}
}
public function getAccountTypeAttribute()
{
return $this->details()->where('name', 'userNumber')->first()->pivot->details;
}
According to your responses in you comments, the way i prefer is this:
1. Make the api call. Check Guzzle to make http requests. It is a nice library and i often use it;
2. Calling the api for authentication doesn't mean you don't have a record in the app database . You need it to related your data to other tables. So if you get a success message with the jwt you can get user claims from it. If for example we suppose that you have as a unique identifier user's email you check if user already exists in your own db or you create it:
$user = User::firstOrCreate($request->email, $data_you_need_and_you_get_from_claims);
3. Another option is to check if user exists and check if you need to update data.
4. Login User
Auth::login($user, $request->has('remember'));
Hope it helps. Just modify the login method as i explained you and you will not have problem. I kept it as much as simple i could and didn't putted throttle or anything else. Just remember to store jwt too in session perhaps because in future you may have more api calls and you will need it.

overridden authenticated method in Login Controller doesn't work

I'm trying to override the authenticated method in the Login Controller but somehow it isn't working. I just tried to simply dd(); but still it doesn't work.
Below is my function code:
public function authenticated(Request $request, $user)
{
dd("hi");
}
What I actually wish to do is as below, but just for simplicity sake, I have dd(); in the function.
public function authenticated(Request $request, $user)
{
if (!$user->verified) {
auth()->logout();
return back()->with('warning', 'You need to confirm your account. We have sent you an activation code, please check your email.');
}
return redirect()->intended($this->redirectPath());
}
Whole controller:
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Auth;
use App\Mail\WelcomeMail;
use Illuminate\Support\Facades\Mail;
class LoginController extends Controller
{
/*
|--------------------------------------------------------------------------
| Login Controller
|--------------------------------------------------------------------------
|
| This controller handles authenticating users for the application and
| redirecting them to your home screen. The controller uses a trait
| to conveniently provide its functionality to your applications.
|
*/
use AuthenticatesUsers;
/**
* Where to redirect users after login.
*
* #var string
*/
protected $redirectTo = '/home';
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('guest')->except('logout');
}
public function login(Request $request)
{
if (Auth::attempt(['email' => $request->email, 'password' => $request->password, 'isActive' => '1']))
{
return view('homepage');
}
else
{
return $this->sendFailedLoginResponse($request, 'auth.failed_status');
}
}
protected function authenticated(Request $request, $user)
{
dd("HI");
// auth()->logout();
return back()->with('warning', 'You need to confirm your account. We have sent you an activation code, please check your email.');
// if(!$user->verified)
// {
// auth()->logout();
// // Auth::logout();
// // \Auth::guard('web')->logout();
// // added logout here
// return back()->with('warning', 'You need to confirm your account. We have sent you an activation code, please check your email.');
// }
// return redirect()->intended($this->redirectPath());
}
}
Kindly ignore the extra commented code in the authenticated function in the controller.
That's because you are overwriting the login function, hence the authenticated function is never called.
If you take a look at the trait:
public function login(Request $request)
{
$this->validateLogin($request);
// If the class is using the ThrottlesLogins trait, we can automatically throttle
// the login attempts for this application. We'll key this by the username and
// the IP address of the client making these requests into this application.
if ($this->hasTooManyLoginAttempts($request)) {
$this->fireLockoutEvent($request);
return $this->sendLockoutResponse($request);
}
if ($this->attemptLogin($request)) {
return $this->sendLoginResponse($request);
}
// If the login attempt was unsuccessful we will increment the number of attempts
// to login and redirect the user back to the login form. Of course, when this
// user surpasses their maximum number of attempts they will get locked out.
$this->incrementLoginAttempts($request);
return $this->sendFailedLoginResponse($request);
}
As you can see, the function sendLoginResponse is the one that is calling the authenticated function.
protected function sendLoginResponse(Request $request)
{
$request->session()->regenerate();
$this->clearLoginAttempts($request);
return $this->authenticated($request, $this->guard()->user())
?: redirect()->intended($this->redirectPath());
}
Therefore, in your case, it should be something like this, to regenerate the session and clear the attempts:
return $this->sendLoginResponse($request);
Or if you want to skip directly to the authenticated function:
return $this->authenticated($request, auth()->user());
And your function should look like this:
public function login(Request $request)
{
if (Auth::attempt(['email' => $request->email, 'password' => $request->password, 'isActive' => '1']))
{
// Updated this line
return $this->sendLoginResponse($request);
// OR this one
// return $this->authenticated($request, auth()->user());
}
else
{
return $this->sendFailedLoginResponse($request, 'auth.failed_status');
}
}

Laravel Socialite Login validate

I have created a laravel project to login with socialite recently.
I have an deactivate account function for Admin. I have my codes to prevent my users to login if their status is 1 (which is deactivated) but these codes doesn't work with user who use socialite function to login.
My codes to prevent deactivate user to login as shown below.
protected function authenticated($request, $user){
if(Auth::attempt(['email' => $request->email, 'password' => $request->password, 'status' => 0]))
{
if($user->role == 2)
{
return redirect()->intended('/admin/users');
}else{
return redirect()->intended('/');
}
}else{
Auth::logout();
return back()->with('error', 'Your account is deactivated.');
}
}
Controller for socialite
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\SocialAccountService;
use Socialite;
use App\User;
class SocialAuthController extends Controller
{
public function FacebookRedirect()
{
return Socialite::driver('facebook')->redirect();
}
public function FacebookCallback(SocialAccountService $service)
{
$fbUser = $service->FacebookCreateOrGetUser(Socialite::Driver('facebook')->user());
auth()->login($fbUser);
return redirect()->to('/');
//$facebookUser = Socialite::driver('facebook')->user();
//$facebookFirstnameAccess = $facebookUser->user['first_name'];
//echo $facebookFirstnameAccess;
//dd($facebookUser);
}
public function GoogleRedirect()
{
return Socialite::driver('google')->redirect();
}
public function GoogleCallback(SocialAccountService $service)
{
$Guser = $service->GoogleCreateOrGetUser(Socialite::Driver('google')->user());
auth()->login($Guser);
//$googleUser = Socialite::driver('google')->user();
return redirect()->to('/');
//$fName = $googleUser->firstname = $googleUser->user['name']['givenName'];
//$lName = $googleUser->lastname = $googleUser->user['name']['familyName'];
//echo $lName;
//dd($googleUser);
}
}
Is there anywhere for me to prevent the user to login with socialite if I have deactivated their account?

Auth::attempt doesn't work [Laravel]

I've looked through all other questions on this...
So I set up a userSeeder which autopopulates my User table:
public function run()
{
$users = [
[
"email" => "email#myemail.co.uk",
"fname" => "Nicola",
"sname" => "Elvin",
"password"=>Hash::make("password")
]
];
foreach ($users as $user)
{
User::create($user);
}
}
My table shows this is stored, and password has been hashed.
In my login function:
$credentials = [
"email" => Input::get("email"),
"password" => Input::get("password")
];
if (Auth::attempt($credentials)) {
return Redirect::route("user/profile");
}else{
echo 'wrong';
}
I did a print_r of $credentials and it correctly displays my email address and password.
Yet it always shows up as wrong. It doesn't ever validate.
USER MODEL
use Illuminate\Auth\UserInterface;
use Illuminate\Auth\Reminders\RemindableInterface;
class User extends Eloquent implements UserInterface, RemindableInterface {
protected $table = 'user';
protected $hidden = array('password');
public function getAuthIdentifier()
{
return $this->getKey();
}
public function getAuthPassword()
{
return $this->password;
}
public function getReminderEmail()
{
return $this->email;
}
}
I figured it out. Embarrassingly, I had white space at the end of my email address...so it wasn't actually correct as I hadn't trimmed it...
Although the way I figured this out was by seeing the sql query that auth:attempt was running by installing a Laravel 4 profiler

Categories