CodeIgniter: routing & authentication - codeigniter

The idea is to catch any access to controller's functions and, if we are authenticated, rout as normal and, if not, show the login form.
The question is, is _remap function the best place to check for access to controller's functions and how to pass routing back to CI in case we are authenticated?

_remap isn't necessary for this. You could use it, but you don't need to.
Check for access in the __construct() method of the controller. You can get the current method via $this->router->fetch_method() and authenticate against that.
Better yet, have all your controller that need this extend a base controller (aka "MY_Controller"). You can write an Auth_Controller and do the auth check in the __construct() there. You can get the current class via $this->router->fetch_class(), as well as the method, just make sure your controllers that need this extend Auth_Controller instead of the usual CI_Controller.
If they shouldn't have access, just redirect them where they need to go or show an error.

make a library called Authentication and check about your method in this
you can get method and class name by this
$class = $this->CI->router->class;
$method = $this->CI->router->method;
and to check this authentication each time you have enabled the hooks from your config file, attach a post_controller_constructor hook to check authentication each time.

Related

Codeigniter 4 - controllers won't work unless I add them directly to Routes.php

Can anyone tell me:
Do I have to declare all of my controllers in Routes.php in Codeigniter 4?
I can't seem to get a controller to work unless I add it directly to the "Routes.php"
I have created my controllers properly and the Home controller is working after install and setup.
If I add the controller My_page.php :
<?php
namespace App\Controllers;
class My_page extends BaseController{
public function index(){
echo "Controller 'My_page' -> function index() ";
}
}
?>
I get a
: "404 - File Not Found
Sorry! Cannot seem to find the page you were looking for."
If I now add the controller to the rout - i.e.:
$routes->post('my_page', 'My_page::index');
Then my controller works properly and I get the "Controller 'My_page' -> function index() " when I visit www.mydomain.com/my_page
I have also tested:
www.mydomain.com/index.php/my_page
and this makes no difference.
I am using the .htaccess that comes with the download. I have updated the base URL to www.mydomain.com/
The documentation is confusing to me - https://www.codeigniter.com/user_guide/incoming/routing.html#setting-routing-rules ;
it sounds like they are saying have to declare all classes with routes?
Why are my controllers not working without declaring them specifically in Routes.php?
And am I misunderstanding 'setAutoRoute(true)' it also does not seem to work - I expect that I can turn this on and simply create my controllers pretty much like in CI3?
If you don't enable auto-routing you most certainly need to add all routes which you are allowing, anything else will fail with error 404. As #parttimeturtle mentioned - autoroute it is disabled by default since 4.2.
So in short - Yes, you need to add all controllers, their functions and the appropriate http methods. (That includes CLI routes as well)
You can use $route->add(), which will allow all http methods, it's however more secure to explicitly set them with their methods.

No notifications are returned

I am trying to get user's unread notifications though my controller.
This works:
public function notifications(){
return \App\User::find(auth()->user()->id)->unreadNotifications()->limit(5)->get();
}
This doesn't, it returns an empty collection:
public function notifications(){
return auth()->user()->unreadNotifications()->limit(5)->get();
}
Could you tell me what I am missing? Thanks in advance.
Using Laravel 5.8 with Backpack 3.5.
The default auth guard of Laravel is overwitten to use Backpack auth in backpack routes, using the UseBackpackAuthGuardInsteadOfDefaultAuthGuard middleware of the permissions manager package. In the rest of the controller auth() and backpack_auth works normally.
Try this:
public function notifications()
return Auth::user()->unreadNotifications()->limit(5)->get();
}
As said in the docs:
You may access the authenticated user via the Auth facade:
Alternatively, once a user is authenticated, you may access the authenticated user via an Illuminate\Http\Request instance. Remember, type-hinted classes will automatically be injected into your controller methods:
Auth and auth() likely don't work here because you're using the Backpack For Laravel authentication which uses a different guard than the default one Laravel uses.
This would probably work for you:
backpack_user()->unreadNotifications()->limit(5)->get();
If that works, here's why:
If you take a look at project/vendor/backpack/base/src/helpers.php you'll see that backpack_user() is an alias for backpack_auth()->user() and backpack_auth does a:
return \Auth::guard(backpack_guard_name());
That's the important bit because it grabs the guard defined config/backpack/base.php (which is backpack by default) and uses that instead of Laravel's default guard of web.

Where to check if an User is logged in in a Laravel Application?

I've been using your advice and View::sharing all of my important data to all views. However, there is one issue I have encountered.
This code:
if(!Auth::guest()){
$user=Auth::user()->id;
}
else $user=0;
$temp=DB::select('query');
View::share('cartnumber', count($temp));
View::share('cartitems', $temp);
doesn't work when put in AppServiceProvider. Or better, it always sets $user=0, even if I am logged in. I thought it is because AppServiceProvider's boot function executes before the site checks if someone is logged in.
I then tried to use a BaseController with a construct function but that doesn't work either. The only solution that seems to work correctly is putting the code in every single Controller for every view! That actually works, which kind of confirms my theory.
But is there anywhere I can put this code without having to copy/paste it in every single Controller? Thanks in advance!
You'd likely want to put this code later in the request life cycle to guarantee an auth user because as others have mentioned middleware/session code has not occured during this part of the framework booting up. You could use a service class to call in all your controllers to avoid the copy pasting. Or If you'd like to achieve this using code in your service provider you could use a View Composer instead of a share this allows you to define a callback/or class that will be called right before the view is returned
view()->composer(['/uri-that-needs-data'], function ($view) {
if (Auth::check()) {
$cart = DB::query(...)->get();
$view->with('cartitems', $cart);
}
});
Check out https://laravel.com/docs/5.7/views#view-composers for more details.
Auth::user() will be empty until the session middleware has run.
The reason you can't access the user inside your service provider is because that code is run during the "bootstrapping" phase of the application lifecycle, when it's doing things like loading filesystem or cache drivers, long before the request is sent through response handlers (including middleware).
Once the application has been bootstrapped and all service providers
have been registered, the Request will be handed off to the router
for dispatching. The router will dispatch the request to a route or
controller, as well as run any route specific middleware.
Source: https://laravel.com/docs/5.7/lifecycle
If you don't want to copy/paste that code everywhere, then one place to put it is in custom route middleware. You can list it after the auth middleware to guarantee a logged-in user.
Edit: View composers are another really good option, as suggested by #surgiie. The reason these can be set up inside a service provider (unlike your example) is because the view composer registers a callback, but doesn't execute it until a much later stage in the application lifecycle.

Laravel 5 - Is there a way to use built-in authentication but disable registration?

I am building an administrative back-end and thus need to hide public user registration. It appears that if you want to use the built-in Illuminate authentication you need to add
use AuthenticatesAndRegistersUsers to your controller definition. This trait is defined here.
It appears as if it is impossible to disable registration if you want to use the built-in auth handlers... can someone show me wrong?
I'm using Laravel 5.2+ and I found that if you remove the Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers and use just Illuminate\Foundation\Auth\AuthenticatesUsers does the trick too.
Though /register is still accessible and will throw a fatal error.
This page talks about overriding the auth controller. Its worth a read, at a basic level it seems you can add the following lines to app\Http\Controllers\Auth\AuthController.php :
public function getRegister() {
return redirect('/');
}
public function postRegister() {
return redirect('/');
}
So if a user accesses the registration url it will redirect them away to a place of your choosing.
You can have your own form of registration. The only thing Laravel does is make it easy to authenticate on a users table because they create the model, build the db schema for users and provide helper methods to authenticate on that model/table.
You don't have to have a view hitting the registration page... But if you want to use the built in auth you still need to use (or set) a Model and a driver for database connections.
You can just remove that view and/or controller method from the route that links to the registration view and create your own (or seed the database manually).
But, no, you cannot forgo using Eloquent, and the User model and expect to use built in auth. Built in authentication requires that you specify settings in /config/auth.php. You may specific a different model (other than User) and you may specify a different table, but you cannot forgo the configuration completely.
Laravel is very customizable though, so you can achieve what you are looking to do... plus why not use Eloquent, it's nice.
Based on #shoo's answer, working with Laravel 5.2
Add the following lines to app\Http\Controllers\Auth\AuthController.php :
public function showRegistrationForm() {
return redirect('/');
}
public function register() {
return redirect('/');
}

CodeIgniter only allow access to certain controllers when logged in

I have some CodeIgniter controllers which should only be accessed by users who have logged in (i.e. where $this->session->userdata('username') is not null). If a non-authenticated person attempts to access said controllers they should receive:
header('location: /auth/login');
There has got to be a better way to do this than to put a
if (!$this->session->userdata('username'))
header('location: /auth/login');
else
{
[rest of function]
}
in front of every function in the controller...
I know DX_Auth has a similar functionality, but I am not using an authentication plugin and I am not open to doing so.
Thanks!
Mala
Do the user login check when the class is created, so it doesn't matter what function the user is accessing it will check for the session variable and redirect to the login page on failure:
function className()
{
parent::Controller();
if(!$this->session->userdata('username')) header('location: /auth/login');
}
That's the way of calling the __constructor or it's equivalent in codeigniter when you create controllers/models, or at least that's what I understood!

Resources