I'm looking to find the best way to implement site-wide authentication checking in Laravel 5.4
I'm building a website that has a growing number of pages that check for rows in a database assigned to a user. If someone visits a page on the site that carries out this function, and they are not logged in, Laravel will give
"Trying to get property of non-object"
and display its error page.
I need to remove all Laravel error pages from my project, to clean it up, and I'm starting with these errors:
Current solution:
My current solution is that wherever a route makes these checks in a controller, I wrap it in
if (Auth::check()) {
I'm wondering if there is a better solution other than wrapping all such code in this?
Edit
I need to go and learn how middleware works.
Related
The problem
When displaying HTTP error pages (404, 500 and so on), I want to keep the standard design of my current project, including header and footer. My project also includes a registration system. When a user is logged in and receives an error message, he will be redirected to the corresponding error page, but Laravel does not recognize that the user is logged in. That's because custom error pages (located in resources/views/errors/{code}.blade.php don't run through the normal web middleware (for some reasons).
This behavior was already reported a few times, but no sufficient answer was provided. A hacky solution is to set the StartSession middleware to be applied on every request, but this isn't sufficient in my case.
How can I use the Auth/Session middleware on custom error pages anyway?
Solutions that do not fit
I don't want to add the StartSession middleware (or any other) to every request
Related questions and links
Laravel Auth in error pages, Laravel 5.0 custom 404 does not use middleware -> Solution is not wanted
Laravel 5.2 Auth::check() on exception pages (layouts) No good solution
A GitHub issue I opened, because I think that this behavior is not intentional
In coherence with the discussion around the github issue I've opened, here are the two best practices:
Adding the StartSession middleware to the global middleware list is a good pratice, as long as your app doesn't have an API or similar
In the second case, you can query the needed Frontend elements that are influenced by the session (e.g. login/register or profile buttons) by using jQuery and an AJAX call. So you are calling a route where middleware is applied and getting therefore the correct elements. A good example can be found in the GitHub issue I've linked.
I have implemented a CSRF protection for my custom TYPO3 extension (according to the documentation) and it's working nicely for non-authenticated frontend visitors and also for backend admins in frontend. A strange thing I noticed is that an error is thrown, if an non-admin backend user tries to use a form in a frontend plugin:
PHP Catchable Fatal Error: Argument 1 passed to TYPO3\CMS\Core\FormProtection\FormProtectionFactory::getMessageClosure() must be an instance of TYPO3\CMS\Lang\LanguageService, null given
I tested using TYPO3 V. 7.6.10 and 7.6.14. The error occurs in both versions.
I took a look at the source code in the FormProtectionFactory and it seems that $GLOBALS['Lang'] is initialized for admin users in the FE, but empty for normal backend users. In BE, both user groups can access other CSRF protected forms.
According to the official reference of the LanguageService, the LanguageService is usually only available in BE:
This class is normally instantiated as the global variable $GLOBALS['LANG'] It's only available in the backend and under certain circumstances in the frontend
Does anyone know what these certain circumstances are? It is of course possible to log off from BE and visit the forms as an unauthenticated user, but this is obviously very annoying. I think that this is expected behaviour, but I don't understand why the issue only occurs for non admins. Maybe someone has an idea, how to make the form available for non-admin backend users in FE, too?
Any help is highly appreciated.
Thanks!
For the sake of completeness, my invocation of the CSRF token generator, but I think that the 'issue' is in TYPO3 itself (or is expected behaviour):
$this->view->assign("csrfToken", FormProtectionFactory::get()->generateToken($this->extensionName,
$this->controllerContext->getRequest()->getControllerActionName(), $additionalObject));
The TYPO3 devs think that CSRF only applies to users-that-are-logged-in, which is not the case here, and thus CSRF functionality cannot be used at all in the frontend for anonymous users.
See https://forge.typo3.org/issues/77403
I have a Laravel 5.1 app using Sentinal for security. Right now we're just using the two stock groups, Users and Admins. Recently I invited a colleague to start testing my app, so I created a user for him. I forgot to add him to the Admins group. When he logged on in infinite redirect loop started because the authentication redirect sends users to a route called home, but you can't load home if you aren't in Admins, and get redirected back to login. Which redirects you back to home.
This is a business rule, we only want Admins using the part of the app that they need to authenticate to, but we'd like to do something friendlier than sending a 403 if you aren't an Admin. I would like to send Authenticated Users to a specific route, or even just redirect them to a static page.
I think I've almost worn out Google trying to get a clue about how to do this. Seems like this should be easy-peasy. I could start hacking the vendor code, but I can't believe that there isn't a more graceful way to do this.
Sorry if this is a dumb question. I'm fairly new to Laravel.
OK folks, I got this working. I wrote a piece of middleware called RedirectIfNotAdmin.
I couldn't find a Sentry or Guard property/method that could tell me about group membership, so I made plain ol' eloquent models for my users and groups tables. I created a many-to-many between those models. In my middleware I use Sentry to get a user id, with that I instantiate one of my own User models. In my User model I implemented a method isAdmin() which gets the groups for the User and returns true if one of them is 'Admins'.
If that isAdmin() method returns false, I redirect to a page that explains that the user doesn't have permissions.
Quite a bit more elaborate solution than what I expected I would need to write. I really thought rydurham/sentinal would have this pretty much solved. Maybe Sentinal does have a cleaner solution and I'm too dense to find it. If anybody would like to comment on a better way to solve this, I'm all ears.
I'm trying to find a way to get all users browsing on the same page.
I already know how to get all logged users on my website but I'm trying to get all logged users browsing on a specific page.
I don't know if this is possible and how, if it is possible.
Thanks for your help.
if you tell specific page you deal with specific controller.
In this specific controller which render specific template webPage you can valid if the user is authentified.
If authentified you can launch a listener (and only launch this listener in this controller) which create a specific log (or database insert) on user/authentified trig this trigger.
You can also filter users which launch trigger before run the code and categorize your log.
Otherwise (but not very good) is to create a kernel listener which launch anytime and for each user and request you can decide to (according to many others arguments) throw specific action and logger. With this you can create a best engine for log very specific behaviour on your website for each user.
Perhaps you can find if bundle already exist for this...Or detail using of Monolog component of Symfony framework
I'm building an app that allows the app to hit an ACT url which then triggers a module method to create a new entry using the ExpressionEngine API. However, as there is no user logged in / loggin in, it is not allowed to submit an entry to a channel.
What is the best way to do this. Bypass the EE api and submit the entry manually, or log a user in progamatically..but then how would that work with sessions etc etc?
If the answer is to "log a user in" it would be great to see a code sample if possible.
Thanks!
As you mention, there are 2 ways to add a new entry:
manually add the database records
use the Channel Entries API (http://expressionengine.com/user_guide/development/api/api_channel_entries.html)
The main differences are that entries added using the API will:
perform all the usual data validation (ie, fields that are marked as being required must not be empty)
run any 3rd-party extensions that installed
keep the site statistics up to date (eg, the number of posts by the author)
Adding the entry manually is reasonably easy for simple channels, but gets more complicated if you are using 3rd party fieldtypes that use additional tables.
To log a member in you should just need to:
// Get the member's id (the member must have permissions to post entries)
$member_id = 1;
// Create session
$this->EE->session->create_new_session($member_id);
use the channel entries api to add the entry, and then:
// Log user back out
$this->EE->session->destroy();
when you have finished.
You are going to want to take a look at the Auth.php class in ./system/libraries/Auth.php. This class is an abstraction of the authentication API's and allows you to do exactly what you want. The "loggin as user" feature uses these same methods, as well as the member module.
You can also take a look at the Authenticate module (which is free) so you get an idea of how others work with the Auth class.
https://objectivehtml.com/authenticate
Here is some pseudo code for you to use:
// Fetch the member from the DB using whatever logic you need
$this->EE->db->where('username', 'some-username');
$member = $this->EE->db->get('members');
$this->EE->load->library('auth');
// Load a new Auth_result object which logs in the member
$authed = new Auth_result($member->row());
$authed->start_session($cp_session = FALSE);
$member->free_result();
This code should work, but I didn't not have time to execute it, which is why it's considered pseudo code.
I should also add that I am not sure if this even the best way to solve your problem. I am simply answering the questions of "how to programmatically login a user without knowing their password and without submitting a login form."