How can I set a custom time for "remember me" in laravel 4? - laravel

I use Auth::login($user, true); to remember a user's login status. But it remembers for about 5 years. That is too long. How can I customize the "remember me" cookie time?

By taking a look at Laravel's source code, I don't think that's possible. If you really need this behavior, you could try to login users without the remember flag, and create your own cookies.
This is the login function:
public function login(UserInterface $user, $remember = false)
{
...
if ($remember)
{
$this->queuedCookies[] = $this->createRecaller($id);
}
...
}
And this is createRecaller, which is calling the forever method.
protected function createRecaller($id)
{
return $this->getCookieJar()->forever($this->getRecallerName(), $id);
}
However, from user's point of view, I think that checking the remember me checkbox in a login form and have to log in again after X period of time, is annoying. I would only do this if it's a mandatory requirement (for example, legal reasons).

Related

Laravel Auth::User() performance

I have a question that whenever we call Auth::User() then its execute the query to fetch record or it have a saved instance?
Example 1
echo Auth::User()->name;
echo Auth::User()->email;
echo Auth::User()->phone;
Example 2
$userInfo=Auth::User();
echo $userInfo->name;
echo $userInfo->email;
echo $userInfo->phone;
Which one should be used performance wise?
Answer and example
Call to the database will be made only the first time you call Auth::user(), after that Laravel will store the user data and each call after that will get the stored instance rather then query the database again.
You can take a look at the vendor\laravel\framework\src\Illuminate\Auth\SessionGuard.php file under user() method. This is the code I copied from my current project which uses Laravel 7.x and this is the function called by Auth::user().
/**
* Get the currently authenticated user.
*
* #return \Illuminate\Contracts\Auth\Authenticatable|null
*/
public function user()
{
if ($this->loggedOut) {
return;
}
// If we've already retrieved the user for the current request we can just
// return it back immediately. We do not want to fetch the user data on
// every call to this method because that would be tremendously slow.
if (! is_null($this->user)) {
return $this->user;
}
$id = $this->session->get($this->getName());
// First we will try to load the user using the identifier in the session if
// one exists. Otherwise we will check for a "remember me" cookie in this
// request, and if one exists, attempt to retrieve the user using that.
if (! is_null($id) && $this->user = $this->provider->retrieveById($id)) {
$this->fireAuthenticatedEvent($this->user);
}
// If the user is null, but we decrypt a "recaller" cookie we can attempt to
// pull the user data on that cookie which serves as a remember cookie on
// the application. Once we have a user we can return it to the caller.
if (is_null($this->user) && ! is_null($recaller = $this->recaller())) {
$this->user = $this->userFromRecaller($recaller);
if ($this->user) {
$this->updateSession($this->user->getAuthIdentifier());
$this->fireLoginEvent($this->user, true);
}
}
return $this->user;
}
Debugbar options
Also as the comment before me pointed out, it is good to download Debugbar for Laravel https://github.com/barryvdh/laravel-debugbar. It will enable you to take a look into queries being executed, views being rendered, requests being sent, and much more.
Other option is Laravel's native solution https://laravel.com/docs/8.x/telescope. I have never personally used it and IMO the first one is simpler to use.
Notes on good practice
Although both examples will essentially do the same thing, I think it is much better to use the second example. Not because of the performance, but rather to make your code readable in future. If you define the user only one time and assign Auth::user() result to it, in future it will be more obvious what it is, and plus, you can easily change what are you assigning to the $userInfo variable (maybe you want to get user from another guard in future, etc.) without having to change it on N places throughout the code.

How to hide login form after reaching the total of failed login attempts?

I want to hide the login form and display an error message instead, but I can't.
I tried to put the code below that rewrites the action on the controller that shows the form, but the method that checks for too many login attempts doesn't seem to work and never returns true.
public function showLoginForm(Request $request)
{
if (method_exists($this, 'hasTooManyLoginAttempts') &&
$this->hasTooManyLoginAttempts($request) ) {
$seconds = $this->limiter()->availableIn($this->throttleKey($request));
return view('auth.block', array(
'seconds' => $seconds
));
}
return view('auth.login');
}
I managed the authentication process with php artisan make: auth login controller is the default generated by Laravel, the only change is in the action that displays the form.
The function hasTooManyLoginAttempts() needs, in the $request, the username (usually the email) as a key to know if the user has reached his max login attempts.
If, in the $request, there is not the username with a value the function is unable to verify the user login attempts.
So you cannot really know who is the user that wants to get your login form, you know who is only after he submitted the form.
IMHO the only way could be to add a username parameter to the GET request but you shoud provide it with some workarounds: cookies, session etc.
Looking at Laravel's code, it checks for hasTooManyLoginAttempts based on throttleKey and maxAttempts.
The throttleKey is dependent on the user's email and IP address. So the output of the following code is something like: info#example.com|127.0.0.1 and that is your throttleKey.
protected function throttleKey(Request $request)
{
return Str::lower($request->input($this->username())).'|'.$request->ip();
}
Now Laravel gets the user's email (username) from $request->input($this->username()) when you send a POST request, which you don't have access to in the showLoginForm method because it's called on the GET request.
Anyway, if you want to block the login form you'll need to come up with your own unique throttleKey and then override the method. Say you want your throttleKey to be based only on the IP address - which is not recommended. Here's how you do it:
// In LoginController.php
protected function throttleKey(Request $request)
{
return $request->ip();
}

remember me for laravel5.2

Hello guys I want to make the remember me checkbox and I want to save the user info into cookies so next time when try to login he find the user name and password in their fields I try to use :
$rememberMe = false;
if(isset($req->remember_me)) {
$rememberMe = true;
}
if(Sentinel::authenticate($req->all(), $rememberMe)) {
$slug = Sentinel::getUser()->roles()->first()->slug();
}
The cookies was set, I see it in the chrome settings but it does not do as I expect
I'm using laravel 5.2
You can use Cookies
cookie, is a small piece of data sent from a website and stored in a user's web browser while the user is browsing that website. Every time the user loads the website, the browser sends the cookie back to the server to notify the website of the user's previous activity
To create:
$response->withCookie(Cookie::make('name', 'value', $minutes));
To retrieve
$value = Cookie::get('name');
Your question is not to remember the user login.. The question is how to fill the inputs based on saved auth information. You can do that if you print the authentication values in the input value attribute while loading the page.
larval Cookies Docs
Also Laravel has it's own implementation of "Remember Me"
if (Auth::attempt(array('email' => $email, 'password' => $password), true))
{
// The user is being remembered...
}
if (Auth::viaRemember())
{
//
}
More information about https://laravel.com/docs/5.4/authentication#remembering-users
There is two main thing need to taken care:
1) You must pass a bool value as second parameter to the method, make sure you cast it before passing it to the method. - In your code, it's perfect
$credentials = $req->only('LOGINNAME', 'PASSNAME')
if(Sentinel::authenticate($credentials , $req->has('remember_me'))){
//Other stuff
}
2) you can verify it works by ensuring a cookie is set with the key cartalyst_sentinel?
So first change as per 1) option and then check the 2) option, may be this is your answer.

Symfony2 shared users across multiple apps

I have multiple symfony2 applications which share common entities, but use different database settings. Each of these databases has tables user, user_role and role.
Here's the catch: I would like that user to be able to login to app1 by visiting www.myproject.com/app1/login and after changing URL to /app2/ to use existing token ONLY if identical user exists in app2's database (same username, password and salt). Currently it checks only for same username which is, you must agree, quite inconvenient...
I can't really see when refreshUser() is being called... :-/
All apps use same User and Role entities and UserRepository.
Any help would be much appreciated!
UserRepository:
class UserRepository extends EntityRepository implements \Symfony\Component\Security\Core\User\UserProviderInterface{
/** #var User */
private $user;
public function loadUserByUsername($username) {
/** #var $Q \Doctrine\ORM\Query */
$Q = $this->getEntityManager()
->createQuery('SELECT u FROM CommonsBundle:User u WHERE u.username = :username')
->setParameters(array(
'username' => $username
));
$user = $Q->getOneOrNullResult();
if ( $user == null ){
throw new UsernameNotFoundException("");
}
return $this->user = $user;
}
public function refreshUser(UserInterface $user) {
return $this->loadUserByUsername($user->getUsername());
}
public function supportsClass($class) {
return $class === 'CommonsBundle\Entity\User';
}
public function findById($id){
return $this->getEntityManager()
->createQuery('SELECT u FROM CommonsBundle:User u WHERE u.id = :id')
->setParameters(array(
'id' => $id
))
->getOneOrNullResult();
}
}
User#equals(UserInterface):
I know there is a prettier way to write this method but I will rewrite it after see this working :)
public function equals(UserInterface $user)
{
if (!$user instanceof User) {
return false;
}
if ($this->password !== $user->getPassword()) {
return false;
}
if ($this->getSalt() !== $user->getSalt()) {
return false;
}
if ($this->username !== $user->getUsername()) {
return false;
}
return true;
}
Your question made me think. When using symfony2 security, you got one problem: Either a session is valid, meaning the user is authenticated as either anonymous or real user, or the session is invalid.
So, with this in mind, I don't see your approach working as you would like it, because let's say user1 logs in and is using app1. Now he switches to app2 and is not in the database, meaning he should not have access. What to do now? Invalidate the session? This would mean he has to log in again in app1.
If you would use subdomains, you could tie your session to that subdomain, but this would mean the user has to log in again for each application.
There is another problem: It seems like symfony2 stores the id of the user into the session, so without access to the app1 database, you cannot know what the password and the roles of the user in the app1 database are and cannot check for it.
I guess the security of symfony2 was simply not made for such behaviour. It expects the session to relate to the same user within your whole application.
I don't think that symfony2 is the big problem here but the overall handling with php. Let's think for one moment what I would suggest without symfony2:
When a user logs in, store user and roles into a specific array in the session, like:
user.app1 = array('username','password',array('role1','role2'))
Now, on each request to app1 I would check if user.app1 is in the session and read the roles from there. If not, I would check for user.app2, user.app3 and so on. If I find none, redirect to login. If I find one, I would query the database to find the user with the same username and compare the other values. If match, store everything into the database. If not, check next user from session.
I looked up the symfony security reference, and you got some extension points, so maybe you can work from there on. The form_login got a success_handler, so adding the array to the session as suggested above should be done there. The firewall itself has some parameters like request_matcher and entry_point which could be used to add additional checks like the ones I mentioned above. All are defined as services, so injecting the entity manager and the security context should be no problem.
I personally think the design itself is not optimal here and you might be better of refactoring your code to either use one user for all apps and different roles (remember that you can define many entity managers and use different databases) or even consolidating all databases and storing everything into one database, using acl to prevent users from viewing the "wrong" content.

Anyway to redirect to previous URL after registration in Joomla?

I am developing a component that required login at some level, then if user is not logged in, I placed a login link, that take user to login page with following in query string.
return=<?php echo base64_encode($_SERVER['REQUEST_URI']);?>
After login, it comes back to that page, but is there some way to tackle this if user is not registered and user starts registering? Is there some way to do this without changing some thing in Joomla it self? like by just setting some thing in cookie e.t.c. Or I will need to change some thing in Joomla Registration component or module. Or is there some plugin for that?
Any response will be appreciated, please tell what ever way you know so that it may give me some better clue.
In your component you could try to store the referrer in the Joomla! session - I don't believe the session changes or is replaced during login. I haven't had time to try this but it should work.
To Save:
$session = JFactory::getSession();
$session->set('theReferrer', $_SERVER['HTTP_REFERER'], 'mycomponentname');
To Retrieve:
$session = JFactory::getSession();
$redirectTo = $session->get('theReferrer', '', 'mycomponentname');
Then you can just use a setRedirect before you return.
$this->setRedirect($redirectTo);
You can achieve this with a plugin (at least in Joomla 3.x - not sure how far back this will work off-hand). Key here is the onUserAfterSave event, which tells you whether the user is new or existing.
I wrote the code below some time ago, so can't recall the exact reason the redirect could not be done from within the onUserAfterSave event handler, but I think the redirect is subsequently overridden elsewhere in the core Joomla user management code if you try to do it from there, hence saving a flag in the session and checking it in a later event handler.
class PlgUserSignupRedirect extends JPlugin
{
public function onUserAfterSave($user, $isnew, $success, $msg)
{
$app = JFactory::getApplication();
// If the user isn't new we don't act
if (!$isnew) {
return false;
}
$session = JFactory::getSession();
$session->set('signupRedirect', 1);
return true;
}
function onAfterRender() {
$session = JFactory::getSession();
if ($session->get('signupRedirect')) {
JFactory::getApplication()->redirect($_SERVER['HTTP_REFERER']);
$session->clear('signupRedirect');
}
}
}

Resources