Laravel 5.1 extra field for authentication - php

I'm making my first big project using Laravel 5.1 and I'd like to add an extra check during user login to see if the user has activated their account.
This is the schema of the users table
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('username');
$table->string('email')->unique();
$table->string('password', 60);
$table->rememberToken();
$table->boolean('is_admin')->default(true);
$table->boolean('is_active')->default(true);
$table->timestamps();
});
I've tried adding a $credentials['is_active'] = true; after $credentials = $this->getCredentials($request); in AutheticatesUser#postLogin and it works but I want to have a custom error if the user's account isn't active because the default one(These credentials do not match our records.) is not that intuitive for the user.
Any suggestions in achieving that?
Thank you!

You can override the postLogin method in your AuthController and check whether the user is active or not like this.
class AuthController extends Controller
{
public function postLogin(Request $request){
$this->validate($request, [
'email' => 'required|email', 'password' => 'required',
]);
$credentials = $this->getCredentials($request);
// This section is the only change
if (Auth::validate($credentials)) {
$user = Auth::getLastAttempted();
if ($user->is_active) {
Auth::login($user, $request->has('remember'));
return redirect()->intended($this->redirectPath());
} else {
return redirect($this->loginPath()) // Change this to redirect elsewhee
->withInput($request->only('email', 'remember'))
->withErrors([
'active' => 'Please active your account'
]);
}
}
return redirect($this->loginPath())
->withInput($request->only('email', 'remember'))
->withErrors([
'email' => $this->getFailedLoginMessage(),
]);
}
}

You can check following way
if(Auth::attempt(['email'=>$email,'password'=>$password,'is_admin'=>1]))
{
return redirect()->intended('admin/dashboard');
}

Related

Change the default Authentification fields (email ,password ) in Laravel

By default, Laravel uses the email and password fields for authentication , I want to change the default fileds for authentication and set the code_massar , date_naissance fields as default
any help !!
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string("code_massar");
$table->date("date_naissance");
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
I use breez package as Authentification Method !
I found one method in laravel 5
Check this post. It's with ldap but it should be usefull i think https://ldaprecord.com/docs/laravel/v2/auth/database/laravel-breeze/#introduction
Go to authenticate method of your LoginController and modify it as your need
public function authenticate(Request $request)
{
$credentials = $request->validate([
'code_massar' => ['required'],
'date_naissance' => ['required'],
]);
if (Auth::attempt($credentials)) {
$request->session()->regenerate();
return redirect()->intended('dashboard');
}
return back()->withErrors([
'code_massar' => 'The provided code_massar do not match our records.',
'date_naissance' => 'The provided date_naissance do not match our records.',
]);
}
you can see more here https://laravel.com/docs/9.x/authentication#authenticating-users

SQLSTATE[HY000]: General error: 1364 Field 'firstname' doesn't have a default value (SQL: insert into `users` (`email`) values (test#test.com))

I am new to Laravel framework.
I am facing an issue, with migration of User table.I added nullable to 'firstname' of my table, which works but displaying the same error for 'lastname'column. I have included nullable() to every column, which is not the right way to do it. How to solve this?? Can anyone please suggest.
User migration table, facing issue with the 'firstname' column.
create_user_table.php
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('firstname');
$table->string('lastname');
$table->string('email')->unique();
$table->date('dob');
$table->char('address',100);
$table->bigInteger('phonenumber');
});
}
UserController with store
UserController.php
public function store(Request $request)
{
$request->validate([
'firstname'=>'required',
'lastname'=>'required',
'email'=>'required',
]);
$user=new User([
$user->firstname=>$request->get('firstname'),
'lastname'=>$request->get('lastname'),
'email'=>$request->get('email'),
'dob'=>$request->get('dob'),
'address'=>$request->get('address'),
'phonenumber'=>$request->get('phonenumber')
]);
$user->save();
return redirect('/users')->with('success','user added');
}
The easiest way to achieve this is:
public function store(Request $request)
{
$request->validate([
'firstname'=>'required',
'lastname'=>'required',
'email'=>'required',
]);
$user=new User();
$user->firstname = $request->firstname;
$user->lastname = $request->lastname;
$user->email = $request->email;
$user->dob = $request->dob;
$user->address = $request->address;
$user->phonenumber = $request->phonenumber;
$user->save();
return redirect('/users')->with('success','user added');
}
Also in your model, you have to add this line for mass assignment
protected $fillable = ['firstname','lastname','email','dob','address','phonenumber'];
You may check out this link for mass assignment: https://laravel.com/docs/7.x/eloquent#mass-assignment
There is an errors in the code you posted,
Here is the fix:
public function store(Request $request)
{
$request->validate([
'firstname'=>'required',
'lastname'=>'required',
'email'=>'required',
]);
$user=new User([
'firstname' => $request->get('firstname'), // $user->firstname=>$request->get('firstname'),
'lastname'=> $request->get('lastname'),
'email' => $request->get('email'),
'dob' => $request->get('dob'),
'address' => $request->get('address'),
'phonenumber' => $request->get('phonenumber')
]);
$user->save();
return redirect('/users')->with('success','user added');
}
also here you are using mass assignment so you should add all used columns to your fillable array in your User model.
Here is a link on what is mass assignment

Validate Additional User Field in Login with Laravel default Authentication

I have this migrations:
Schema::create('users', function (Blueprint $table) {
$table->bigIncrements('id');
$table->bigInteger('company_id')->unsigned();
$table->foreign('company_id')->references('id')->on('companies')->onDelete('cascade');
$table->boolean('enable')->default(0);
$table->string('name', 120)->nullable();
$table->string('surname', 120)->nullable();
$table->string('email', 120)->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->bigInteger('counter')->default(0);
$table->string('url_address', 160);
$table->string('ip', 25)->nullable();
$table->boolean('isCompany')->default(0);
$table->boolean('isMailing')->default(0);
$table->text('content')->nullable();
$table->string('nip1', 12)->nullable();
$table->string('business1', 120)->nullable();
$table->string('phone1', 60)->nullable();
$table->string('street1', 150)->nullable();
$table->string('number1', 8)->nullable();
$table->string('postal_code1', 12)->nullable();
$table->string('city1', 100)->nullable();
$table->bigInteger('country_id1')->default(0);
$table->bigInteger('provincial_id1')->default(0);
$table->string('nip2', 12)->nullable();
$table->string('business2', 120)->nullable();
$table->string('phone2', 60)->nullable();
$table->string('street2', 150)->nullable();
$table->string('number2', 8)->nullable();
$table->string('postal_code2', 12)->nullable();
$table->string('city2', 100)->nullable();
$table->bigInteger('country_id2')->default(0);
$table->bigInteger('provincial_id2')->default(0);
$table->string('nip3', 12)->nullable();
$table->string('business3', 120)->nullable();
$table->string('phone3', 60)->nullable();
$table->string('street3', 150)->nullable();
$table->string('number3', 8)->nullable();
$table->string('postal_code3', 12)->nullable();
$table->string('city3', 100)->nullable();
$table->bigInteger('country_id3')->default(0);
$table->bigInteger('provincial_id3')->default(0);
$table->decimal('cash', 9, 2)->default(0);
$table->decimal('lng', 10, 8)->default(0);
$table->decimal('lat', 10, 8)->default(0);
$table->boolean('enable_map')->default(0);
$table->rememberToken();
$table->timestamps();
$table->engine = "InnoDB";
});
I have 2 questions in connection with logging in to Laravel:
I would like to be able to log in only if the user has enable = 1
The parameter enable is the default value of 0. After clicking the activation link in the mail I would like to change enable = 0 on enable = 1
How can I do this?
When calling the attempt() method you can pass an array of credentials that can be used.
You can do as mentioned previously and create your own controllers, but if you're using the auth scaffolding that comes with laravel (This includes auth:make and the classes in app/Http/Controllers/Auth) you can simply edit the file:
app/Http/Controllers/Auth/LoginController.php
In here you want to override the credentials method by adding the following:
protected function credentials(Request $request)
{
return array_merge($request->only($this->username(), 'password'), ['active' => 1]);
}
This means that when the rest of the code kicks in automatically, it'll make the credentails array look something like:
array(
'username' => 'theusername',
'password' => 'thepassword',
'active' => 1
)
It was mentioned previously that you should cast your attribute to a boolean, but this is not true. Laravel migrations create a tiny int column instead of a boolean, and the casting only works when dealing with models. Since this array is used to generate where conditions on the DB query, casting won't work as the value in the DB will be 1 not true.
For that you have to make custom login controller and handle this situation.
I am mentioning this in detail check me below given steps.
Update your routes/web.php
Route::get('/', function () {
return redirect(route('login'));
});
Route::get('/home', 'HomeController#index')->name('home');
Route::post('/authenticate', 'LoginController#authenticate')->name('authenticate');
Route::get('/logout', '\App\Http\Controllers\Auth\LoginController#logout');
Create app/Http/Controllers/LoginController.php
and add this method into this controller
/**
* Handle an authentication attempt.
*
* #param \Illuminate\Http\Request $request
*
* #return Response
*/
public function authenticate(Request $request)
{
//ADD VALIDATION CODE HERE
$credentials = $request->only('email', 'password');
if (Auth::attempt($credentials)) {
// Authentication passed...
return redirect()->intended('dashboard');
}
}
So I have mentioned in above method "//ADD VALIDATION CODE HERE
" at that place you have to validate request and make query to check that user is enabled or not.
I hope this will work for you.
You will have to override the default controllers and routes.
First remove the auth routes as you are going to create them yourself.
Then define your controllers.
For the login part you can create your own Login Controller and in there make your own login attempt which is what Laravel uses. There you can add your desired attribute validations like this.
public function login(Request $request)
{
//Validate your form data here
$request->validate([
'email' => ['required', 'string'],
'password' => ['required', 'string'],
]);
//Create your own login attempt here
$login_atempt = Auth::attempt([
'email' => $request->email,
'password' => $request->password,
'enabled' => true //or 1 , I recommend you to cast your attribute to boolean in your model
], $request->filled('remember'));
if ($login_atempt) {
$request->session()->regenerate();
return redirect()->route('home'); //Your home screen route after successful login
}
//using custom validation message as Laravel does
throw ValidationException::withMessages([
'email' => [trans('auth.failed')],
]);
}
also add a simple method to call the login form.
public function showLoginForm()
{
return view('auth.login');
}
Then your routes (I named my controller, UserLoginController)
Route::group(['middleware' => 'guest'], function () {
Route::get('/login', 'UserLoginController#showLoginForm')->name('login.index');
Route::post('/login', 'UserLoginController#login')->name('login');
});
For the second question Laravel documentation states
After an email address is verified, the user will automatically be redirected to /home. You can customize the post verification redirect location by defining a redirectTo method or property on the VerificationController:
protected $redirectTo = '/dashboard';
So you can make your own controller that handles that enable attribute change and redirection.
To finish, make sure you manually add the auth routes you need.

Laravel 5 form with file

I have a table like this:
Schema::create('partners', function (Blueprint $table) {
$table->increments('id');
$table->binary('image');
$table->string('name');
$table->string('link');
$table->timestamps();
});
Then, after validation, I need to add data from forms, defined as this:
{{Form::file('image')}} I tried this way:
public function newPartner(Request $request) {
$validator = Validator::make($request->all(), [
'name' => 'required',
'link' => 'required'
]);
if ($validator->fails()) {
return redirect('partners/create')->withErrors($validator);
}
Partner::create($request->all());
return redirect('/');
}
But it doesn't fill the binary field with the uploaded image.
How can I achieve this?
Thank you for helping me.

Laravel 5.1 login with mfa token

I'm trying to get the a login with mfa to work. I'm using the https://github.com/antonioribeiro/google2fa package.
Basically the user-migration looks like this
class CreateUsersTable extends Migration {
/**
* Run the migrations.
*
* #return void
*/
public function up() {
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('email')->unique();
$table->string('password', 60);
$table->rememberToken();
$table->string('google2fa_secret');
$table->boolean('useMfa')->default(false);;
$table->timestamps();
});
}
...
If the user has not yet activated mfa I create a new secret every time the user opens the profile page.
if(!$user->useMfaToken()){
$google2fa = new Google2FA();
$user->google2fa_secret = $google2fa->generateSecretKey();
$user->save();
$google2fa_url = $google2fa->getQRCodeGoogleUrl(
'DatenPro.de',
$user->email,
$user->google2fa_secret
);
}
If the user enters the secret for finalizing the activation of mfa this will be executed:
public function saveMfa(){
$user = \Auth::user();
$secret = \Input::get('secret');
$google2fa = new Google2FA();
$valid = $google2fa->verifyKey($user->google2fa_secret, $secret);
if($valid){
$user->useMfa = true;
$user->save();
return redirect()->back()->withMessage('mfa sucessfully activated');
}
...
Now I'm working on the login with a mfa-token. I want that the user has the option to enter the token at the login page, if he has already activated it, otherwise if the mfa-Checkbox is deselected the "secret" text-input is hidden.
Email: __________
Password: __________
Use Mfa: [x]
Secret: __________
Where do I have to put the checks of the mfa token? I have read about it to check it through a middleware and a session-variable, but this seems kind of wrong.
Just figured it out before posting.
You can implement a "authenticated"-method in the AuthController.
This could look like this:
public function authenticated($request, $user){
if($user->useMfaToken()){
$secret = \Input::get('secret');
$google2fa = new Google2FA();
$validMfaToken = $google2fa->verifyKey($user->google2fa_secret, $secret);
}else{
$validMfaToken = true;
}
if($validMfaToken){
return redirect()->intended('dashboard');
}
Auth::logout();
return redirect($this->loginPath)
->withInput($request->only('email', 'remember'))
->withErrors([
'secret' => 'mfa token was not corret',
]);
}

Categories