Check for active user state with laravel - php

This is pretty standard login function and validation that works nicely. But I also want to check that the user is active. I have set up a column in my users table with 'active' set to either 0 or 1.
public function post_login()
{
$input = Input::all();
$rules = array(
'email' => 'required|email',
'password' => 'required',
);
$validation = Validator::make($input, $rules);
if ($validation->fails())
{
return Redirect::to_route('login_user')
->with_errors($validation->errors)->with_input();
}
$credentials = array(
'username' => $input['email'],
'password' => $input['password'],
);
if (Auth::attempt($credentials))
{
// Set remember me cookie if the user checks the box
$remember = Input::get('remember');
if ( !empty($remember) )
{
Auth::login(Auth::user()->id, true);
}
return Redirect::home();
} else {
return Redirect::to_route('login_user')
->with('login_errors', true);
}
}
I've tried something like this already:
$is_active = Auth::user()->active;
if (!$is_active == 1)
{
echo "Account not activated";
}
But this can only be used within the 'auth attempt' if statement and at that point the users credentials(email and pass) are already validated. So even if the users account if not active at this point they are already logged in.
I need a way to return validation to let them know they still need to activate their account and check if their account is set at the same time their email and pass are being checked.

Filters are the way to go. It's easy and clean to solve this problem, see my example below.
Route::filter('auth', function()
{
if (Auth::guest())
{
if (Request::ajax())
{
return Response::make('Unauthorized', 401);
}
else
{
return Redirect::guest('login');
}
}
else
{
// If the user is not active any more, immidiately log out.
if(Auth::check() && !Auth::user()->active)
{
Auth::logout();
return Redirect::to('/');
}
}
});

Can't you use something like this:
if (Auth::once($credentials))
{
if(!Auth::user()->active) {
Auth::logout();
echo "Account not activated";
}
}

Just make the active field one of the confirmations. You can do this:
$credentials = array(
'username' => $input['email'],
'password' => $input['password'],
'active' => 1
);
if (Auth::attempt($credentials))
{
// User is active and password was correct
}
If you want to specifically tell the user they are not active - you can follow it up with this:
if (Auth::validate(['username' => $input['email'], 'password' => $input['password'], 'active' => 0]))
{
return echo ('you are not active');
}

A better solution might be to create an Auth driver that extends the Eloquent Auth driver already in use and then override the attempt method.
Then change your auth config to use your driver.
Something like:
<?php
class Myauth extends Laravel\Auth\Drivers\Eloquent {
/**
* Attempt to log a user into the application.
*
* #param array $arguments
* #return void
*/
public function attempt($arguments = array())
{
$user = $this->model()->where(function($query) use($arguments)
{
$username = Config::get('auth.username');
$query->where($username, '=', $arguments['username']);
foreach(array_except($arguments, array('username', 'password', 'remember')) as $column => $val)
{
$query->where($column, '=', $val);
}
})->first();
// If the credentials match what is in the database we will just
// log the user into the application and remember them if asked.
$password = $arguments['password'];
$password_field = Config::get('auth.password', 'password');
if ( ! is_null($user) and Hash::check($password, $user->{$password_field}))
{
if ($user->active){
return $this->login($user->get_key(), array_get($arguments, 'remember'));
} else {
Session::flash('authentication', array('message' => 'You must activate your account before you can log in'));
}
}
return false;
}
}
?>
In your login screen, check for Session::get('authentication') and handle accordingly.
Alternatively, allow them to log in but don't let them access any pages other than one that offers a link to resend the activation email.

This is what I do:
if (\Auth::attempt(['EmailWork' => $credentials['EmailWork'], 'password' => $credentials['Password']], $request->has('remember'))) {
if (\Auth::once(['EmailWork' => $credentials['EmailWork'], 'password' => $credentials['Password']])) {
if (!\Auth::user()->FlagActive == 'Active') {
\Auth::logout();
return redirect($this->loginPath())
->withInput($request->only('EmailWork', 'RememberToken'))
->withErrors([
'Active' => 'You are not activated!',
]);
}
}
return redirect('/');
}
return redirect($this->loginPath())
->withInput($request->only('EmailWork', 'RememberToken'))
->withErrors([
'EmailWork' => $this->getFailedLoginMessage(),
]);

Related

Shorten the Controller Logic Laravel

I'm trying using Laravel login authentication using different guards but I found that there is some repetition within the store method in the Login Controller (the only difference is the guard used, all other logic are the same). I just can't find a way to shorten them into some other logic such as method(function) which can be reusable. So if there is possible way, Please help me out.
public function store(Request $request)
{
$request->validate([
'username' => 'required',
'password' => 'required'
]);
if (Auth::guard('instructor')->attempt(['email' => $request->username, 'password' => $request->password])) {
if (auth('instructor')->user()->status === Instructor::HAS_DEACTIVATED) {
$request->session()->flush();
Auth::guard('instructor')->logout();
return redirect('login')->with(
'error',
'Your Account has being deactivated . Please Contact your Administrator!');
}
return redirect(route('instructor.dashboard'));
}
if (Auth::guard('student')->attempt(['email' => $request->username, 'password' => $request->password])) {
if (auth('student')->user()->status === Student::HAS_DEACTIVATED) {
$request->session()->flush();
Auth::guard('student')->logout();
return redirect('login')->with(
'error',
'Your Account has being deactivated . Please Contact your Administrator!');
}
return redirect(route('student.dashboard'));
}
return back()->with('error', 'Credentials provided do not match any record.');
}
You can create a separate function and then call that function.
public static function deleteSession($gaurd)
{
$request->session()->flush();
Auth::guard($gaurd)->logout();
return redirect('login')->with(
'error',
'Your Account has being deactivated . Please Contact your Administrator!');
}
Then in your store function call deleteSession statically.
if (auth('instructor')->user()->status === Instructor::HAS_DEACTIVATED)
{
self::deleteSession('instructor'); //change gaurd according to your need
}
This is probably not the best way to go about this, I'm sure there is a better solution, and #Aqib Javaed's seems to be it, but here's one way to shorten the code a bit that I could manage. It's not perfect but does the job done.
public function store(Request $request)
{
$request->validate([
'username' => 'required',
'password' => 'required'
]);
if (Auth::guard('instructor')->attempt(['email' => $request->username, 'password' => $request->password])) {
$userType = 'instructor';
} elseif (Auth::guard('student')->attempt(['email' => $request->username, 'password' => $request->password])) {
$userType = 'student';
} else {
return back()->with('error', 'Credentials provided do not match any record.');
}
$modelName = ucwords($userType); //turn the user type to its corresponding model name
if (auth('$userType')->user()->status === $modelName::HAS_DEACTIVATED) {
$request->session()->flush();
Auth::guard('$userType')->logout();
return redirect('login')->with(
'error',
'Your Account has being deactivated . Please Contact your Administrator!');
}
return redirect(route("$userType.dashboard"));
}

Laravel: using throttle in a custom Login controller

This is my login controller function
use ThrottlesLogins;
protected $maxLoginAttempts = 3;
protected $lockoutTime = 300;
public function login(Request $request)
{
if ($this->hasTooManyLoginAttempts($request))
{
$this->fireLockoutEvent($request);
return $this->sendLockoutResponse($request);
}
$validator = Validator::make(Input::all() , ['credential' => 'required|min:2|max:255', 'password' => 'required|string|min:8', ]);
$cred = $request->credential;
$pw = $request->password;
$remember = (Input::has('remember')) ? true : false;
if (filter_var($cred, FILTER_VALIDATE_EMAIL))
{
if (Auth::guard('customers')->attempt(['email' => $cred, 'password' => $pw, 'verified' => 1], $remember))
{
return redirect()->route('front');
}
else
{
return redirect()->route('customer-login-page')->with('error', 'Your credentials do not match');
}
}
else
{
if (Auth::guard('customers')->attempt(['contact' => $cred, 'password' => $pw], $remember))
{
return redirect()->intended(route('front'));
}
else
{
return redirect()->route('customer-login-page')->with('error', 'Your credentials do not match');
}
}
}
protected function hasTooManyLoginAttempts(Request $request)
{
return $this->limiter()->tooManyAttempts(
$this->throttleKey($request), $this->maxLoginAttempts, $this->lockoutTime
);
}
It's not working. I've tried failed login attempts more that 3 times and still not getting throttled. AND
Even when I post the correct credentials, the login and redirect works but when I check the request I get a
302 FOUND error
in the network tab
You need to let the trait know that you are performing a login attempt by calling $this->incrementLoginAttempts($request) (see code). You can place this call right after your existing throttle check:
if ($this->hasTooManyLoginAttempts($request))
{
$this->fireLockoutEvent($request);
return $this->sendLockoutResponse($request);
}
$this->incrementLoginAttempts($request);
// other code
Try
use Illuminate\Foundation\Auth\ThrottlesLogins;
Instated of
use ThrottlesLogins;

Allow login using username or email in Laravel 5.4

Now I've followed the Laravel documentation on how to allow usernames during authentication, but it takes away the ability to use the email. I want to allow users to use their username or email to login. How do I go about this?
I've added this code to the LoginController as per Laravel's Documentation and it only allows username for login. I want it to accept username or email for login.
public function username () {
return 'username';
}
I think a simpler way is to just override the username method in LoginController:
public function username()
{
$login = request()->input('login');
$field = filter_var($login, FILTER_VALIDATE_EMAIL) ? 'email' : 'username';
request()->merge([$field => $login]);
return $field;
}
Follow instructions from this link: https://laravel.com/docs/5.4/authentication#authenticating-users
Then you can check for the user input like this
$username = $request->username; //the input field has name='username' in form
if(filter_var($username, FILTER_VALIDATE_EMAIL)) {
//user sent their email
Auth::attempt(['email' => $username, 'password' => $password]);
} else {
//they sent their username instead
Auth::attempt(['username' => $username, 'password' => $password]);
}
//was any of those correct ?
if ( Auth::check() ) {
//send them where they are going
return redirect()->intended('dashboard');
}
//Nope, something wrong during authentication
return redirect()->back()->withErrors([
'credentials' => 'Please, check your credentials'
]);
This is just a sample. THere are countless various approaches you can take to accomplish the same.
Open your LoginController.php file.
Add this reference
use Illuminate\Http\Request;
And override the credentials method
protected function credentials(Request $request)
{
$field = filter_var($request->get($this->username()), FILTER_VALIDATE_EMAIL)
? 'email'
: 'username';
return [
$field => $request->get($this->username()),
'password' => $request->password,
];
}
Successfully tested in Laravel 5.7.11
You need to override protected function attemptLogin(Request $request) method from \Illuminate\Foundation\Auth\AuthenticatesUsers Trait in your LoginController
i.e. in my LoginController class
protected function attemptLogin(Request $request) {
$identity = $request->get("usernameOrEmail");
$password = $request->get("password");
return \Auth::attempt([
filter_var($identity, FILTER_VALIDATE_EMAIL) ? 'email' : 'username' => $identity,
'password' => $password
]);
}
Your LoginController class should use Trait \Illuminate\Foundation\Auth\AuthenticatesUsers in order to override attemptLogin method i.e.
class LoginController extends Controller {
use \Illuminate\Foundation\Auth\AuthenticatesUsers;
.......
.......
}
I think its even more simple, just override the method from AuthenticatesUsers traits, credentials method in your LoginController. Here I have implemented to login with either email or phone. You can change it to fit your needs.
LoginController.php
protected function credentials(Request $request)
{
if(is_numeric($request->get('email'))){
return ['phone'=>$request->get('email'),'password'=>$request->get('password')];
}
return $request->only($this->username(), 'password');
}
This is the way I do it:
// get value of input from form (email or username in the same input)
$email_or_username = $request->input('email_or_username');
// check if $email_or_username is an email
if(filter_var($email_or_username, FILTER_VALIDATE_EMAIL)) { // user sent his email
// check if user email exists in database
$user_email = User::where('email', '=', $request->input('email_or_username'))->first();
if ($user_email) { // email exists in database
if (Auth::attempt(['email' => $email_or_username, 'password' => $request->input('password')])) {
// success
} else {
// error password
}
} else {
// error: user not found
}
} else { // user sent his username
// check if username exists in database
$username = User::where('name', '=', $request->input('email_or_username'))->first();
if ($username) { // username exists in database
if (Auth::attempt(['name' => $email_or_username, 'password' => $request->input('password')])) {
// success
} else {
// error password
}
} else {
// error: user not found
}
}
I believe there is a shorter way to do that, but for me this works and is easy to understand.
public function username()
{
//return ‘identity’;
$login = request()->input('identity');
$field = filter_var($login, FILTER_VALIDATE_EMAIL) ? 'email' : 'phone';
request()->merge([$field => $login]);
return $field;
}
protected function validateLogin(Request $request)
{
$messages = [
'identity.required' => 'Email or username cannot be empty',
'email.exists' => 'Email or username already registered',
'phone.exists' => 'Phone No is already registered',
'password.required' => 'Password cannot be empty',
];
$request->validate([
'identity' => 'required|string',
'password' => 'required|string',
'email' => 'string|exists:users',
'phone' => 'numeric|exists:users',
], $messages);
}
https://dev.to/pramanadiputra/laravel-how-to-let-user-login-with-email-or-username-j2h
This solution of "Rabah G" works for me in Laravel 5.2. I modified a litle but is the same
$loginType = request()->input('useroremail');
$this->username = filter_var($loginType, FILTER_VALIDATE_EMAIL) ? 'email' : 'username';
request()->merge([$this->username => $loginType]);
return property_exists($this, 'username') ? $this->username : 'email';
Thanks, this is the solution I got thanks to yours.
protected function credentials(Request $request) {
$login = request()->input('email');
// Check whether username or email is being used
$field = filter_var($login, FILTER_VALIDATE_EMAIL) ? 'email' : 'user_name';
return [
$field => $request->get('email'),
'password' => $request->password,
'verified' => 1
];
}

Laravel email confirm login

Ok so what i'm trying todo, do not let login if user has not confirmed his account by email. My login code looks like that:
public function postLogin()
{
$credentials = [
'confirmed' => 0,
'email' => Input::get('email'),
'password' => Input::get('password')
];
$user = Sentinel::authenticate($credentials, false); // Login the user (if possible)
if ($user and $user->banned) {
Sentinel::logout();
$user = null;
}
if ($user) {
return $this->afterLoginActions();
} else {
$this->alertFlash(trans('app.access_denied'));
return Redirect::to('auth/login');
}
}
But i can still login without any errors. Any help? Thanks guys!
Edited: working, but now i dont get flash message if my details are incorect.
Code:
public function postLogin()
{
$credentials = [
'email' => Input::get('email'),
'password' => Input::get('password'),
'confirmed' => 1
];
$user = Sentinel::authenticate($credentials, false); // Login the user (if possible)
if ($user and $user->banned) {
Sentinel::logout();
$this->alertFlash(trans('app.banned'));
$user = null;
}
if ($user->confirmed==1) {
return $this->afterLoginActions();
}
else if ($user->confirmed==0) {
Sentinel::logout();
$this->alertFlash(trans('app.not_active'));
return Redirect::to('auth/login');
} else {
$this->alertFlash(trans('app.access_denied'));
return Redirect::to('auth/login');
}
}
Do you have a column in your table storing the information if this user passed the email confirmation? If you have one, this is what I do it with typical Laravel postLogin method.
public function postLogin(Request $request)
{
$credentialas = (your credential here);
// only check credentials
if ($this->guard()->once($credentials)) {
$currentStatus = $this->guard()->user()->status;
if (intval($currentStatus) === (NOT_CONFIRMED)) {
$this->guard()->logout();
return $this->sendSuspendedResponse($request);
} else {
$this->guard()->login($this->guard()->user());
return $this->sendLoginResponse($request);
}
}
}

update profile password laravel 5

I am working in laravel 5.1 and my update profile was working but will not encrypted and not working now.
When I try to update the user table will also password_confirmation field and causes a conflict in the database. I do not understand.
In the form says successfully but the database does not update any
Code
public function updatePassword() {
$passwordData = Input::except('_token');
$validation = Validator::make($passwordData, User::$passwordData);
if ($validation->passes()) {
array_forget($passwordData,'password_confirmation');
User::where(array(
'password' => Hash::make(Input::get('password'))
));
Session::flash('password', 'Perfil editado com sucesso');
return Redirect::to('backend/perfil/password');
} else {
return Redirect::to('backend/perfil/password')->withInput()->withErrors($validation);
}
}
user
public static $passwordData = array(
'password' => 'required|confirmed',
'password_confirmation' => 'required'
);
Follow this simple steps to get rid of anything
Step 1 : Get the password from the form
$PasswordData = Input::all();
Step 2 : Validate your password
Validator::extend('pwdvalidation', function($field, $value, $parameters) {
return Hash::check($value, Auth::user()->password);
});
Step 3 : Define the validation rule in your User Model
public static $rulespwd = array('OldPassword' => 'required|pwdvalidation',
'NewPassword' => 'required|confirmed|alphaNum|min:5|max:10',
'NewPassword_confirmation' => 'required',
);
Note : You shall define your own rule according to your need
Step 4 : If the rule is passed, then update else throw error messages to your view
$validator = Validator::make($PasswordData, User::$rulespwd, $messages);
if ($validator->passes()) {
$user = User::find(Auth::user()->id);
$user->password = Input::get('NewPassword');
$user->save();
return Redirect::to(Session::get('urlpath') . '/changepassword')->withInput()->with('Messages', 'The Password Information was Updated');
} else {
return Redirect::to(Session::get('urlpath') . '/changepassword')->withInput()->withErrors($validator);
}

Categories