I'm having some trouble with laravel 5.4 authentication.
Out of the box the auth worked although I couldn't access Auth::user().
After some changes that had to be made for FrontEnd considerations, I added a new login function that uses Auth::attempt($credentials) like so:
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Support\Facades\Input;
use App\Models;
use Auth;
use Log;
class LoginController extends Controller
{
use AuthenticatesUsers;
/**
* Where to redirect users after login.
*
* #var string
*/
protected $redirectTo = '/home-page';
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('guest')->except('logout');
}
public function login(){
if(Auth::guest()){
if (Auth::attempt(['email' => Input::get('email'), 'password' => Input::get('password')])) {
Log::debug(Auth::user());
return redirect('/home-page');
}
}
return 'cannot log in';
}
}
The login passes, the redirect works, and Auth::user() is accessible.
The problem is that after the redirect ,all routes guarded by 'auth' middleware are not accessible.
Route::group(['middleware' => 'auth'], function(){
Route::get('some-route', function(){
return view('some-view');
}
});
Moreover, I tried to see if I can access the user there but Auth::user() returns null.
Notes:
1. User table is the one that was created by the Laravel user table migration.
2. Registering users via RegisterController (got from php artisan make:auth)
3. Only change in auth.php is this:
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],
],
Would love to hear new suggestions, I can't figure what's wrong here.
Related
I use Laravel UI for authentication. In my user table, I have a field called telephone. Can I use to log in the user with that telephone and password with Laravel UI Authentication? I tried to change the contents in App/Http/Controllers/Auth/LoginController.php but couldn't figure out how this works. Really appreciate it if somebody could help. Thanks.
App/Http/Controllers/Auth/LoginController.php,
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
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 = RouteServiceProvider::REDIRECT;
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('guest')->except('logout');
}
}
You can put this on your LoginController to override the Laravel default.
public function username()
{
return 'telephone';
}
By adding this function in your App\Http\Controllers\LoginController.php, You can override the login method
public function login(Request $request)
{
$request->validate([
'mobile' => 'required',
'password' => 'required',
]);
$credentials = $request->only('mobile', 'password');
if (Auth::attempt($credentials)) {
URL::to('home');
}
return redirect("login")->withSuccess('Oppes! You have entered invalid credentials');
}
If you are using fortify
edit config/fortify.php
'username' => 'telephone',
in the username key replace the value with the field which you want for login
By default, Laravel uses the email field for authentication. If you would like to customize this, you may override username method on your LoginController:
public function username()
{
return 'telephone';
}
I have two guards in laravel
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
//Our Admin custom driver
'web_admin' => [
'driver' => 'session',
'provider' => 'admins',
],
],
and providers
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
//Admin user provider
'admins' => [
'driver' => 'eloquent', //We are using eloquent model
'model' => App\Admin::class,
],
],
The default is
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
When i log in as admin and try to access the user profile it asks me to login as user which is normal. But what im looking for is, admin should be able to access whole site as admin login.
The reason i choose multi auth over rbac is because i have 5 types of users and each have different registration fields and login. Each user have a set of tools too.
So i want admin guard to be able to access all guards too.
Business guard to be able to access only users guard.
App/Http/Controllers/AdminAuth/LoginController
<?php
//LoginController.php
namespace App\Http\Controllers\AdminAuth;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
//Class needed for login and Logout logic
use Illuminate\Foundation\Auth\AuthenticatesUsers;
//Auth facade
use Auth;
class LoginController extends Controller
{
//Where to redirect admin after login.
protected $redirectTo = '/admin/home';
//Trait
use AuthenticatesUsers;
//Custom guard for admin
protected function guard()
{
return Auth::guard('web_admin');
}
//Shows admin login form
public function showLoginForm()
{
return view('admin.auth.login');
}
}
App/Http/Controllers/Auth/LoginController
<?php
namespace App\Http\Controllers\Auth;
use Socialite;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
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');
}
/**
* Redirect the user to the GitHub authentication page.
*
* #return \Illuminate\Http\Response
*/
public function redirectToProvider($social)
{
return Socialite::driver($social)->redirect();
}
/**
* Obtain the user information from GitHub.
*
* #return \Illuminate\Http\Response
*/
public function handleProviderCallback($social)
{
$user = Socialite::driver($social)->user();
// $user->token;
}
}
Similarly i have created middleware for admin too in App/Https/Middleware/AuthenticateAdmin.php
<?php
//AuthenticateAdmin.php
namespace App\Http\Middleware;
use Closure;
//Auth Facade
use Auth;
class AuthenticateAdmin
{
public function handle($request, Closure $next)
{
//If request does not comes from logged in admin
//then he shall be redirected to admin Login page
if (! Auth::guard('web_admin')->check()) {
return redirect('/admin/login');
}
return $next($request);
}
}
And RedirectIfAdminAuthenticated
<?php
//RedirectIfAdminAuthenticated.php
namespace App\Http\Middleware;
use Closure;
//Auth Facade
use Auth;
class RedirectIfAdminAuthenticated
{
public function handle($request, Closure $next)
{
//If request comes from logged in user, he will
//be redirect to home page.
if (Auth::guard()->check()) {
return redirect('/home');
}
//If request comes from logged in admin, he will
//be redirected to admin's home page.
if (Auth::guard('web_admin')->check()) {
return redirect('/admin/home');
}
return $next($request);
}
}
RedicrectIfAuthenticated
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Auth;
class RedirectIfAuthenticated
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #param string|null $guard
* #return mixed
*/
public function handle($request, Closure $next, $guard = null)
{
if (Auth::guard($guard)->check()) {
return redirect('/home');
}
return $next($request);
}
}
Further to our correspondence
1.
If you have many types of users... so i suggest you to change your logic and make the Admin as User too... remove the admins and in the users add field "type" or something like that... and work with field to check if user is admin or have permission / access to some parts of the system... and if the user "type" is "admin" so he will have access to all parts too.
so you mean remove multi auth and go for RBAC. But i have a requirement where i need to use multi auth and each guard has their own RBAC For example, admin guard roles are manager, support and so. Business guard roles are vendors, sellers and so.
yes this is what i mean. I did similar thing on one of the systems that i developed, and i added one more guard so all the "logged in" routes pass in (like auth) and there i'm checking the requested rout and action and check if the user type is allow to access this action, and if not i redirected him to somewhere else (in my case to main dashboard page).
add new middleware
php artisan make:middleware Permissions
in app\Http\Kernel.php, add to protected $routeMiddleware new middleware
'permissions' => \App\Http\Middleware\Permissions::class,
in Routes web add the desire routs for logged in and add the middleware permissions ... pay attention to the as definition
Route::group(['middleware'=>['auth', 'permissions']], function() {
// any of your routs ... for example
Route::get('/', [
'uses'=>"UserController#getUsers",
'as'=>"users"
]);
Route::get('/{id}', [
'uses'=>"UserController#getUserEdit",
'as'=>"users.edit"
]);
});
in the new middleware app\Http\Middleware\Permissions.php,
adjust the public function handle and add there the users level logic... pay attention that for the switch case checking the as ... the same as that defined in the routs web file.
add more check as you need for the logged in user "type"... Admin, Support ... and so on as you have in the system.
public function handle($request, Closure $next, $guard = null)
{
$user = $request->user();
$actions = $request->route()->getAction();
switch( $actions['as'] ) {
case "users":
if( ! $user->isAdmin() ) {
//return redirect()->route("dashboard");
}
break;
case "users.edit":
if( ! $user->isAdmin() ) {
}
break;
// add more cases as you need and check the user "type"
default:
break;
}
return $next($request);
}
if you have a lot of routs... so maybe it will be better to add few "little" middleware and for every route group / prefix ... check if user allow to access this prefix.
for example... add SupportMiddleware / SalesMiddleware ... and in every one of them you can just check the user type and if it's fit to the current group of routes.
Simply, seperate your guards with , (comma) then all of the listed guards can access those routes.
Example:
Route::group(['middleware'=>'auth:web,web_admin'], function() {
//Now this routes can be accessible by both admin as well as
});
How can i Show error to user saying Your account is not activated yet, please verify your Account if the activated column in users table is 0 in laravel 5.4
Here is my Login
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
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 username()
{
return 'username';
}
public function credentials(Request $request)
{
return [
'username' => $request->username,
'password' => $request->password,
'activated' => 1,
];
}
Currently if user is not activated it says, Credentials do not match. I founded an old question on stackoverflow that says override your postLogin function AuthController but in laravel 5.4 authcontroller do not exist
The easiest way would be overwrite the authenticated() method which is called after the user logs in and then check there if it is activated:
public function credentials(Request $request)
{
return [
'username' => $request->username,
'password' => $request->password,
];
}
protected function authenticated(Request $request, $user)
{
if ( !$user->activated ) {
auth()->logout();
return back()->withErrors(['email' => 'Your account is not activated yet, please verify your Account.']);
}
return redirect()->intended($this->redirectPath());
}
Also note that you have to add a similar $user->activated check in your auth middleware, because otherwise users would be able to login trough forgotten password page.
I am new in laravel app development. When I am using auth middleware, then it works fine for unregistered user(redirecting to login page). But when logged user going to visit that page, then its redirecting to home page (root directory).
below the route from routes.php code is
Route::group(['middleware' => 'auth'], function () {
Route::resource('/edit', 'userController#edit');
});
Below my userController.php code is
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\allUsers;
class userController extends Controller
{
public function index(){
}
public function show($id){
}
public function edit(){
return view('auth.user_edit');
}
}
Below my authController code is
<?php
namespace App\Http\Controllers\Auth;
use App\User;
use Validator;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ThrottlesLogins;
use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;
class AuthController extends Controller
{
/*
|--------------------------------------------------------------------------
| Registration & Login Controller
|--------------------------------------------------------------------------
|
| This controller handles the registration of new users, as well as the
| authentication of existing users. By default, this controller uses
| a simple trait to add these behaviors. Why don't you explore it?
|
*/
use AuthenticatesAndRegistersUsers, ThrottlesLogins;
/**
* Where to redirect users after login / registration.
*
* #var string
*/
protected $redirectTo = '/dashboard';
/**
* Create a new authentication controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware($this->guestMiddleware(), ['except' => 'logout']);
}
/**
* Get a validator for an incoming registration request.
*
* #param array $data
* #return \Illuminate\Contracts\Validation\Validator
*/
protected function validator(array $data)
{
return Validator::make($data, [
'name' => 'required|max:255',
'email' => 'required|email|max:255|unique:users',
'password' => 'required|min:6|confirmed',
]);
}
/**
* Create a new user instance after a valid registration.
*
* #param array $data
* #return User
*/
protected function create(array $data)
{
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => bcrypt($data['password']),
]);
}
}
Anyone help me please.
You can overwrite the $redirectTo variable in your AuthController:
/**
* Where to redirect users after login / registration.
*
* #var string
*/
protected $redirectTo = '/dashboard';
Update:
Try Changing your route:
Route::group(['middleware' => 'auth'], function () {
Route::get('edit', 'userController#edit');
});
Route::resource creates all CRUD routes for your automatically.
https://laravel.com/docs/5.1/controllers#restful-resource-controllers
Yes Problem solved. Just changed the route
Route::group(['middleware' => ['web', 'auth']], function () {
Route::get('/edit', 'userController#edit');
});
I am new to Laravel however and I am following the tutorial on http://www.codeanchor.net/blog/complete-laravel-socialite-tutorial/, to login a user through Facebook into my application. However, almost everywhere I find a tutorial using either Github or Twitter for the Socialite Plugin provided in Laravel.
My problem is that on following everything in the tutorial, as I click on the "Login to Facebook" button, it throws an "Invalid Argument Exception" with No Socialite driver was specified.".
Another stack overflow question seemed to narrow things down:
https://stackoverflow.com/questions/29673898/laravel-socialite-invalidargumentexception-in-socialitemanager-php-line-138-n
Stating that the problem is in the config/services.php
Now, i have the app_id and app_secret. However, the redirect link seems to be confusing as I can't find it on Facebook either. I am aware that this is where my app should go to Facebook for login, however, unsure of what it should be.
Does anyone have any idea on this.
In your composer.json add- "laravel/socialite": "~2.0",
"require": {
"laravel/framework": "5.0.*",
"laravel/socialite": "~2.0",
the run composer update
In config/services.php add:
//Socialite
'facebook' => [
'client_id' => '1234567890444',
'client_secret' => '1aa2af333336fffvvvffffvff',
'redirect' => 'http://laravel.dev/login/callback/facebook',
],
You need to create two routes, mine are like these:
//Social Login
Route::get('/login/{provider?}',[
'uses' => 'AuthController#getSocialAuth',
'as' => 'auth.getSocialAuth'
]);
Route::get('/login/callback/{provider?}',[
'uses' => 'AuthController#getSocialAuthCallback',
'as' => 'auth.getSocialAuthCallback'
]);
You also need to create controller for the routes above like so:
<?php namespace App\Http\Controllers;
use Laravel\Socialite\Contracts\Factory as Socialite;
class AuthController extends Controller
{
public function __construct(Socialite $socialite){
$this->socialite = $socialite;
}
public function getSocialAuth($provider=null)
{
if(!config("services.$provider")) abort('404'); //just to handle providers that doesn't exist
return $this->socialite->with($provider)->redirect();
}
public function getSocialAuthCallback($provider=null)
{
if($user = $this->socialite->with($provider)->user()){
dd($user);
}else{
return 'something went wrong';
}
}
}
and finally add Site URL to your Facebook App like so:
Update 2018 - laravel 5.6 - socialite 3.0
It's little bit tricky for something that looks/should be easy, but anyway this is how i make things works for me.
Server side
you can find those instructions and more details in socialite docs
Installation
composer require laravel/socialite
Configuration
in config/services.php add
'facebook' => [
'client_id' => env('FACEBOOK_CLIENT_ID'),
'client_secret' => env('FACEBOOK_CLIENT_SECRET'),
'redirect' => env('FACEBOOK_CALLBACK_URL'),
],
in .env file add
FACEBOOK_CLIENT_ID=paste_client_id_here
FACEBOOK_CLIENT_SECRET=paste_client_secret_here
FACEBOOK_CALLBACK_URL=https://www.example.com/auth/facebook/callback
in routes/web.php add
Route::get('auth/facebook/', 'Auth\FacebookController#redirect')->name('auth.facebook');
Route::get('auth/facebook/callback', 'Auth\FacebookController#callback')->name('auth.facebook.callback');
in App\Http\Controllers\Auth add new controller FacebookController.php
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\User;
use Socialite;
class FacebookController extends Controller {
/**
* Create a new controller instance.
*
* #return void
*/
public function redirect()
{
return Socialite::driver('facebook')->redirect();
}
/**
* Create a new controller instance.
*
* #return void
*/
public function callback(Request $request)
{
try {
$facebookAccount = Socialite::driver('facebook')->user();
// your logic here...
return redirect()->route('your.route.name');
} catch (Exception $e) {
return redirect()->route('auth.facebook');
}
}
}
Facebook side
go to https://developers.facebook.com/apps and create new app (if you don't have one already)
and make sur your app settings are like below in those screen shots:
Important note
If you are developing in your local machine, you have to use tools like ngrok that provide a secure link to your localhost.
In the facebook login settings change https://www.example.com with the url provided by ngrok something like https://8b0215bc.ngrok.io.
It is the only way that worked for me while developing in my local machine.
Create a provider under your config/services.php file
'facebook' => [
'client_id' => 'your-fb-client-id',
'client_secret' => 'your-fb-secret',
'redirect' => 'http://your-redirect.com/route',
],
now you can create a controller with following code
//this function will redirect users to facebook login page
public function facebook()
{
return \Socialize::with('facebook')->redirect();
}
public function callback()
{
$user = \Socialize::with('facebook')->user();
//now we have user details in the $user array
dd($user);
}
and this is your route
Route::get('facebook', 'LoginController#facebook');
Route::get('callback', 'LoginController#callback');
Step 1: Install latest version of Laravel, using below command:
composer create-project --prefer-dist laravel/laravel facebookLogin
Step 2: Install Socialite
composer require laravel/socialite
Step 3: Create Facebook app
You have to go https://developers.facebook.com and create app for facebook login client id and secret key. Once you create account make sure you copy client id and secret key.
Now you have to set app id, secret and call back url in config file in your laravel code:
config/services.php
return [
....
'facebook' => [
'client_id' => 'app id',
'client_secret' => 'add secret',
'redirect' => 'http://localhost:8000/auth/facebook/callback',
],
]
There can be multiple configs added in the services file like facebook, github, twitter etc.
Step 4: Add Database Column
php artisan make:migration add_facebookId_column_users_table
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AddFacebookIdColumn extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up() {
Schema::table('users', function ($table) {
$table->string('facebook_id')->nullable();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down() {
// rollback code
}
}
Step 5: Update User Model:
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Fortify\TwoFactorAuthenticatable;
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable {
use HasApiTokens;
use HasFactory;
use HasProfilePhoto;
use Notifiable;
use TwoFactorAuthenticatable;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'name',
'email',
'password',
'facebook_id'
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password',
'remember_token',
'two_factor_recovery_codes',
'two_factor_secret',
];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
/**
* The accessors to append to the model's array form.
*
* #var array
*/
protected $appends = [
'profile_photo_url',
];
}
Step 6: Setup Routes in app/Http/routes.php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\FacebookController;
Route::get('auth/facebook', [FacebookController::class, 'redirectToFacebook']);
Route::get('auth/facebook/callback', [FacebookController::class, 'handleFacebookCallback']);
Step 7: Add Facebook Controller app/Http/Controllers/FacebookController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Laravel\Socialite\Facades\Socialite;
use Exception;
use App\Models\User;
use Illuminate\Support\Facades\Auth;
class FacebookController extends Controller {
/**
* Create a new controller instance.
*
* #return void
*/
public function redirectToFacebook() {
return Socialite::driver('facebook')->redirect();
}
/**
* Create a new controller instance.
*
* #return void
*/
public function handleFacebookCallback() {
try {
$user = Socialite::driver('facebook')->user();
$finduser = User::where('facebook_id', $user->id)->first();
if($finduser) {
Auth::login($finduser);
return redirect()->intended('dashboard');
} else{
$newUser = User::create([
'name' => $user->name,
'email' => $user->email,
'facebook_id'=> $user->id,
'password' => encrypt('123456dummy')
]);
Auth::login($newUser);
return redirect()->intended('dashboard');
}
} catch (Exception $e) {
dd($e->getMessage());
}
}
}