I am trying to use Laravel's HTTP Basic Authentication in a Lumen project.
On the routes.php file, I set the auth.basic middleware for the rout I need to authenticate:
$app->get('/test', ['middleware' => 'auth.basic', function() {
return "test stuff";
}]);
On bootstrap.php I have registered the middleware and the auth service provider:
$app->routeMiddleware([
'auth.basic' => Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
]);
[...]
$app->register(App\Providers\AuthServiceProvider::class);
But when I try to test the route by visiting http://lumen/test I get the following error:
Fatal error: Call to undefined method Illuminate\Auth\RequestGuard::basic() in C:\source\lumen\vendor\illuminate\auth\Middleware\AuthenticateWithBasicAuth.php on line 38
Does anyone know how can I get the code of the guard for basic authentication?
Thanks.
Ran into a similar problem, wanted to use basic auth for users in the database, so ended up writing my own AuthServiceProvider and registered that in bootstrap/app.php
Here is the class, maybe it will help you in your case.
<?php
namespace App\Providers;
use App\User;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\ServiceProvider;
class HttpBasicAuthServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* #return void
*/
public function register()
{
//
}
/**
* Boot the authentication services for the application.
*
* #return void
*/
public function boot()
{
$this->app['auth']->viaRequest('api', function ($request) {
$email = $_SERVER['PHP_AUTH_USER'];
$password = $_SERVER['PHP_AUTH_PW'];
if ($email && $password) {
$user = User::whereEmail($email)->first();
if (Hash::check($password, $user->password)) {
return $user;
}
}
return null;
});
}
}
Related
Unable to find answers anywhere
I am using Laravel 5.5 policy to restrict a user from listing properties that are not registered by the user (authenticated via API).
I have two classes User and HostProperty. Additionally, I have registered a policy for the user to access their hosted property list by ID.
Here are my models.
The Main Problem is not able to call on controller method - which throws above error:
$authUser = auth('api')->user();
if ($authUser->can('access', $property)) {
return response()->json(['success' => 'success']);
} else {
return response()->json(['error' => 'error']);
}
User.php
namespace App;
use Illuminate\Notifications\Notifiable;
use Cartalyst\Sentinel\Users\EloquentUser;
use Illuminate\Database\Eloquent\SoftDeletes;
use Laravel\Passport\HasApiTokens;
use Illuminate\Auth\Authenticatable as AuthenticableTrait;
use Illuminate\Contracts\Auth\Authenticatable;
class User extends EloquentUser implements Authenticatable
{
use HasApiTokens, Notifiable;
use SoftDeletes;
use AuthenticableTrait;
protected $guarded=[];
protected $dates = ['deleted_at'];
protected $hidden = [
'password', 'remember_token',
];
//hosts relation
public function hostproperty()
{
return $this->hasMany('App\Models\Hosts\HostProperty','user_id');
}
}
HostProperty.php
namespace App\Models\Hosts;
use Illuminate\Database\Eloquent\Model;
class HostProperty extends Model
{
public $timestamps = true;
protected $guarded=[];
protected $hidden = [
'user_id',
];
public function user()
{
return $this->belongsTo('App\User','user_id');
}
}
HostPropertyPolicy
namespace App\Policies\Host;
use App\User;
use App\Models\Hosts\HostProperty;
use Illuminate\Auth\Access\HandlesAuthorization;
class HostPropertyPolicy
{
use HandlesAuthorization;
/**
* Create a new policy instance.
*
* #return void
*/
public function __construct()
{
//
}
public function access(User $user, HostProperty $HostProperty)
{return TRUE;
//return $user->id === $HostProperty->user_id;
}
}
AuthServiceProvider
namespace App\Providers;
use Illuminate\Support\Facades\Gate;
use Laravel\Passport\Passport;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use App\Models\Hosts\HostProperty;
use App\Policies\Host\HostPropertyPolicy;
class AuthServiceProvider extends ServiceProvider
{
/**
* The policy mappings for the application.
*
* #var array
*/
protected $policies = [
'App\Model' => 'App\Policies\ModelPolicy',
HostProperty::class=>HostPropertyPolicy::class,
];
/**
* Register any authentication / authorization services.
*
* #return void
*/
public function boot()
{
$this->registerPolicies();
Passport::routes();
}
}
HostPropertyController
use App\User;
use App\Models\Hosts\HostProperty;
use App\Http\Controllers\Controller;
class HostPropertyController extends Controller
{
public function listOneProperty($propertyId)
{
$authUser = auth('api')->user();
$property=HostProperty::with('user')->find($propertyId);
if ($authUser->can('access', $property)) {
return response()->json(['success' => 'success']);
} else {
return response()->json(['error' => 'error']);
}
}
}
Route
Route::get('listOneProperty/{propertyId}', array('as' => 'listOneProperty.get', 'uses' => 'HostPropertyController#listOneProperty'));
Please note: I am calling from API - the above route is for API, I am not able to use the policy on the API routes. I keep getting the above error while calling this route.
I tried
$this->authorize('access', $property);
However, since API doesn't store login session the above could not be completed so I again tried with
$authUser = auth('api')->user();
$authUser->authorize('access', $property);
Does not work either. I have tried all I can but still, I cannot get it done right.
If someone has an example of using Laravel policy in API authenticated by Passport it would be helpful for anybody looking to get this done right.
With regards
Looks like
$authUser = auth('api')->user();
is returning a query instead of a User model.
Please make sure that $authUser is a User model before calling ->can()
However, since API doesn't store login session the above could not be completed so I again tried with
Authentication is typically handled by middleware in Laravel. If you're using Passport, you should be able to use the auth:api middleware to authenticate requests, as long as you're sending the correct Authorization header and token.
Try changing this
$authUser = auth('api')->user();
to this
$authUser = auth()->user();
And add the auth middleware to your route:
Route::get('listOneProperty/{propertyId}', 'HostPropertyController#listOneProperty')
->name('listOneProperty.get')
->middleware('auth:api');
If you're consuming the api from your own web views and you want it to work with the current session, check out the Consuming Your API With JavaScript section of the Passport docs:
https://laravel.com/docs/5.7/passport#consuming-your-api-with-javascript
I have this situation where I have a route /admin which requires Auth middleware to be activated. I have the middleware requirement indicated in the web.php route. Also, I do have the default auth setup of laravel.
The kernel.php does have the middleware indicated too.
But, weirdly enough /admin brings me to a white page with nothing. When logged in, the problem isn't there. It had been working and all of a sudden it was not working anymore.
The auth middleware is as it is:
<?php
namespace App\Http\Middleware;
use Illuminate\Auth\Middleware\Authenticate as Middleware;
class Authenticate extends Middleware
{
/**
* Get the path the user should be redirected to when they are not authenticated.
*
* #param \Illuminate\Http\Request $request
* #return string
*/
protected function redirectTo($request)
{
return route('login');
}
}
The controller:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\NewsletterSubscribers;
use App\User;
use File;
class adminController extends Controller
{
//
public function __construct()
{
$this->middleware('auth');
$this->middleware('admin');
}
public function index(){
return view('admin.home');
}
public function changebg(){
return view('admin.changebg');
}
public function changebgimage(Request $request){
$this->validate($request,
[
'image'=>'required|image|mimes:jpg,JPG,jpeg,JPEG|max:4096|dimensions:max_width:1600,max_height:1100',
]
);
$path="images/";
$imagepath="images/bg.jpg";
if( File::exists($imagepath))
{
unlink($imagepath);
}
if ( ! File::exists($path) )
{
File::makeDirectory($path,0777,true);
}
$getimageName = "bg.jpg";
$request->image->move(public_path($path), $getimageName);
return view('admin.home');
}
public function newslettersubscriberslist(){
$newslettersubscribers= NewsletterSubscribers::all();
$count=0;
return view('admin.subscriberslist',compact('newslettersubscribers','count'));
}
public function registerAdmin(){
return view('auth.adminregister');
}
public function viewAdmins(){
$admins= User::select('users.*')->where('role','=','admin')->get();
//print_r($admins);
$count=0;
return view('admin.adminlist',compact('admins','count'));
}
public function viewUsers(){
$users= User::select('users.*')->where('role','=','user')->get();
//print_r($admins);
$count=0;
return view('admin.userlist',compact('users','count'));
}
}
The admin middleware:
<?php
namespace App\Http\Middleware;
use Closure;
use Auth;
class Admin
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if (Auth::check() && Auth::user()->role == 'admin') {
return $next($request);
}
else {
return redirect('/login');
}
}
}
The the route I'm using:
Route::get('/admin', 'AdminController#index')->name('adminhome')->middleware('auth');
I dont find anything weird here but weirdly enough the problem exists. Can you guys trace somethin unusual here or somewhere it can be??
First of all, make sure you have error reporting turned on. Also take a look at laravel log. Looking at your code the problem might be case of AdminController. In routes you have 'AdminController#index' but the class you showed has name adminController and it should be AdminController. I also don't know what is the name of file but it should be again AdminController.php
You can use the middleware like this
Route::group(['middleware'=>'auth'], function()
{
Route::get('/admin', 'AdminController#index')->name('adminhome');
}
I create a policy called LetterPolicy , this is the code
namespace App\Policies;
use App\Letter;
use App\User;
use Illuminate\Auth\Access\HandlesAuthorization;
class LetterPolicy
{
use HandlesAuthorization;
/**
* Create a new policy instance.
*
* #return void
*/
public function __construct()
{
//
}
public function update(User $user, Letter $letter)
{
return($user->id === $letter->user_id || $user->role_id===1 ) ;
}
}
and this is authserviceprovider
namespace App\Providers;
use App\Letter;
use App\Policies\LetterPolicy;
use App\Policies\UserPolicy;
use App\User;
use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
class AuthServiceProvider extends ServiceProvider
{
/**
* The policy mappings for the application.
*
* #var array
*/
protected $policies = [
'App\Model' => 'App\Policies\ModelPolicy',
User::class => UserPolicy::class,
Letter::class => LetterPolicy::class,
];
/**
* Register any authentication / authorization services.
*
* #return void
*/
public function boot()
{
$this->registerPolicies();
//
}
}
And in the following code I check for the user
class LetterController extends Controller
{
protected $user;
public function __construct()
{
$this->middleware(function ($request, $next){
$this->user = Auth::user();
return $next($request);
});
}
public function edit(Letter $letter)
{
if($this->user->can('update', $letter)){
//edit
}
else
abort('403', 'Access Denied');
}
The code is working well in localhost but on the remote server it reports the access denied error. I created this policy after deploying the site on the server so I create a route /clear-cache with code
Route::get('/clear-cache', function() {
$exitCode = \Illuminate\Support\Facades\Artisan::call('cache:clear');
});
To clear the cache after creating the policy. But it still reports the 403 error. What is the problem?
I tried dd($this->user->id === $letter->user_id || $this->user->role_id===1 ); in the COntroller and it returned false. I tried dd($this->user->id == $letter->user_id || $this->user->role_id==1 ); and it was true. Now it works but I don't know why!!!
Fjarlaegur's answer was the key. I had the same problem: in localhost there was no issue, but in production server somehow every authorization failed and it was because of the comparison operator. Changed from === to == and all as good.
Is there any way available to access Session values in AppServiceProvider? I would like to share session value globally in all views.
You can't read session directly from a service provider: in Laravel the session is handled by StartSession middleware that executes after all the service providers boot phase
If you want to share a session variable with all view, you can use a view composer from your service provider:
public function boot()
{
view()->composer('*', function ($view)
{
$view->with('your_var', \Session::get('var') );
});
}
The callback passed as the second argument to the composer will be called when the view will be rendered, so the StartSession will be already executed at that point
Add new web middleware ShareDataForView
in \app\Http\Kernel.php:
protected $middlewareGroups = [
'web' => [
// ...
\Illuminate\Session\Middleware\StartSession::class,
// I will always ShareDataForView after StartSession
\App\Http\Middleware\ShareDataForView::class,
...
and write your code in method "handle" of app\Http\Middleware\ShareDataForView.php, for example:
<?php
namespace App\Http\Middleware;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Str;
use Closure;
use Log, Exception, View;
class ShareDataForView
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
$user = Auth::user();
$bank = NULL;
if ( $user ){
$bank = $user->bank;
}
View::share('user', $user);
session()->put(['bank' => $bank]);
return $next($request);
}
}
The following works for me on Laravel 5.2, is it causing errors on your app?
AppServiceProvider.php
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
\Session::put('lang', 'en_US');
view()->share('lang', \Session::get('lang', 'de_DE'));
}
/**
* Register any application services.
*
* #return void
*/
public function register()
{
//
}
}
home.blade.php
<h1>{{$lang}}</h1>
Shows "en_US" in the browser.
I have tried injecting the Guard contract into the constructor, I have tried moving around. But when a user is logged in - Auth::check() returns false.
In other files (Except 1 global middleware) Auth::check() works correctly.
In the middleware - moving Auth Check to the top helped alleviate the issue. In this case - it isn't working.
Additional information: This app has been upgraded from 4.2 . Previously it used Confide.
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
if(Auth::check())
{
$user = Auth::user();
$messages=Message::where('read',0);
$messages->where(function ($query) use ($user) {
$query->where('to',$user->id)->orwhere('from',$user->id);
});
$message_unread= $messages->count();
$new_notifications= Notification::where('user_id',$user->id)->where('viewed',0)->count();
}
else
{
$message_unread=0;
$new_notifications=8888888;
//its 888888 for testing purposes.
}
view()->share(([
'message_unread'=>$message_unread,
'new_notifications'=>$new_notifications
]));
}
/**
* Register any application services.
*
* #return void
*/
public function register()
{
//
}
}
You should move this code to controller layer. boot method of Laravel's ServiceProviders serves for bootstrapping the services, not implementing busines logic.
You need to use auth in at the top of the serviceprovider class
use Auth;
Instead of
use Illuminate\Support\Facades\Auth;
Apart from using a view composer, you could also use middleware which is processed after the session variables have been loaded:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Contracts\Auth\Guard;
class SetViewVariables
{
protected $auth;
public function __construct(Guard $auth)
{
$this->auth = $auth;
}
public function handle($request, Closure $next)
{
$user = $this->auth->user();
view()->share('user', $user);
return $next($request);
}
}