Yii2 Logout Specific User - php

How can I tell yii2 to logged out specific user who has login to system?
Let say, there is 2 user is logged in on system, userA and userB.
How can I specified logged out userB?
What I know is userB has to trigger this command to logout.
Yii::$app->user->logout();
return $this->goHome();
But maybe we can use some command like Yii::$app->user->logout('userB');?
Or is it has some other way?

Well, the problem is about how to kill all sessions of the user.
Flag user to force relogin
You can add an additional column force_relogin to User identity class and set it to true when you need to logout someone:
$user = User::findByLogin('userB');
$user->force_logout = 1;
$user->save();
Then add the event handler beforeLogin() on user component like so:
'user' => [
'class' => 'yii\web\User',
'on beforeLogin' => function ($event) {
if ($event->identity->force_logout && $event->cookieBased) {
$event->isValid = false;
}
},
'on afterLogin' => function ($event) {
if ($event->identity->force_logout) {
$event->identity->force_logout = false;
$event->identity->save();
}
}
]
Check, whether $cookieBased and $identity->force_logout are so on...
But that's a bad idea, because the user may have more than one session (logged in in different browsers)
Store list user's sessions in DB
Create table user_sessions with user_id and session_id columns and save each session, you open for that user in the DB. That you can find all sessions of the user and drop them one by one. Something like: (code is not tested, just as an idea)
$sessionId = Yii::$app->session->getId();
session_commit();
foreach (UserSessions::findByUserLogin('userB') as $session) {
session_id($session->id);
session_start();
session_destroy();
session_commit();
}
session_id($sessionId); // Restore original session
session_start();
session_commit();
The idea is weak because you always should take care about consistence of sessions on the server and in the DB.
Store sessions in DB
Store sessions is the database, as described in the Yii2 Guide for Session handling
Then you can just find session in the DB and delete it directly. You shouldn't take care about the consistence and session rotation, because DB is the only place, where the sessions are being stored. As a free bonus you get a non-blocking work with sessions.

If you are still looking for a solution to this, just change the auth_key of the user that you want to logout. This auth_key is used by the system to remember if a user is logged in, thus changing this will invalidate any session that uses this key.
Example to logout a user with id=100
$user = User::findOne(100);
$user->generateAuthKey(); //a function in User (Identity) class that generates the auth_key
$user->save();

If you are using a model User for storing auth credentials, you can simply change the value of 'id' (and also a key '100') to some other integer value, to make user fail auth on his next request.
In other words, you must change all '100', for example to '200' in this code:
file: /models/User.php
private static $users = [
'100' => [
'id' => '100',
'username' => 'admin',
'password' => 'password_for_admin',
'authKey' => '43e02a0f0e5f6a7907b2f2c69a765be7',
'accessToken' => '7b2f2c69a765be743e02a0f0e5f6a790',
],
];

Related

Get a user by username and password with Laravel

I need to do some extra checks on a user, I would like to get the user by username and password.
Firstly:
Is there a built in function that gets a user by username and password without authenticating them?
Secondly:
If the above is no, then how do I correctly hash the password, because if I use Hash::make( $password ) and then compare to the database, it is not the same... You would usually use Hash::check but I need to actually get the user by username and password.
In Laravel 5.2
You can use Auth::once($credentials) to validate credentials and thereafter Auth::getUser(); to get the user.
$credentials = Request::only('username', 'password');
if(!Auth::once($credentials)) {
// Invalid user credentials; throw Exception.
}
$user = Auth::getUser();
First:
If you want to check if user data to authentication is correct you can use:
if (Auth::validate($credentials))
{
//
}
But if you want to get user from database with user and password, you can use:
$user = User::whereName($username)->wherePassword(Hash::make($password))->first();
Second
To store password in database you should use Hash::make($password) as you showed and it works without any problems. Using Auth::validate should solve the issue.
Yes, there is a built in function you should use. I recommend you to read the docs. But here's a good example, it's pretty self-evident:
$input = array(
'username' => Input::get('username'),
'password' => Input::get('password'),
);
$remember = (boolean)Input::get('remember'); //'Remember me' checkbox
if (Auth::attempt($input, $remember)) {
return Redirect::intended('dashboard')->with("success", "You're logged in!"); //Redirect the user to the page intended to go to, with the dashboard page as default
}
Registering a user looks something like this:
$input = array(
'username' => Input::get('username'),
'email' => Input::get('email'),
'password' => Hash::make(Input::get('password')) //Encrypt password
);
$user = User::create($input);
I also recommend you to read about input validation. I hope this helps, good luck.
Edit: I didn't read the "without authenticating them" part. You should use Auth::validate($input) as Marcin already explained.
Laravel 5.7
To check a users credentials without logging them in, I had to do this:
$user = User::whereEmail($request->email)->first();
$user = password_verify($request->password, optional($user)->getAuthPassword()) ? $user : false;
Laravel auth validation makes use of https://www.php.net/manual/en/function.password-verify.php

destroy particular session Among two sessions in codeigniter

I have maintained two sessions with different variable set to true at the time of login in my application in codeigniter. The first session is for the admin and the second is for normal users. Now what i want is when admin logs in then i have to destroy all sessions of normal user and fetch admin data.
My code is as :
for admin login
$query = $this->dbmodel->validate(); //to validate admin//
if ($query) {
// if the user's credentials validated...
$data = array(
'username' => $this->input->post('username'),
'admin_logged_in' => true
);
$this->session->set_userdata($data);
for normal user
$data = array(
'useremail' => $email,
'username' => $name,
'logged_in' => true);
$this->session->set_userdata($data);
Thanks in advance
try to set different session for admin and normal user like
$this->session->set_userdata('normal_user_session_data',$data); // normal user
$this->session->set_userdata('admin_login_session_data',$data); // admin
for unset :-
$this->session->unset_userdata('normal_user_login_session_data');// unset normal user session
$this->session->unset_userdata('admin_login_session_data'); // unset admin session
you can use unset for delete all session stored in userdata.
unset($this->session->userdata);

i want to save both user and admin data on codeigniter session but i cant save both to user_data. so what can i do?

i created a site with admin area and user area using codeigniter. but both admin and user can't log in at same time. because the session user_data is only can use once.
so how can i save another session data?
this is how i save admin data.
private function access_granted(){
$admin_session_data = array(
'username' => $this->input->post('username'),
'is_admin_logged_in' => 1
);
$this->session->set_userdata($admin_session_data);
$this->session->set_flashdata('successed', 'You Logged in Successfully');
$this->login_failed_or_successed();
}
You can set the user info and admin info to session as two separate arrays as,
$user_info=array(
'id'=>$id,
........
);
And
$admin_info=array(
'id'=>$id,
........
);
$this->session->set_userdata(array("users" => $user_info));
and
$this->session->set_userdata(array("admin" => $admin_info));
and unset this as,
$this->session->unset_userdata('users');
$this->session->unset_userdata('admin');

Zend AUTH disable multiple login on diff computer or browser

I have a concern about Zend Auth. I've searched throughout the internet, but haven't found any tutorial, article or discussion;
scenario: Login as 'ADMIN' on 'COMPUTER 01' and 'COMPUTER 02' concurrently.
I want my user login system to prevent the 'ADMIN' user from logging in on two computers at the same time. So that when a User is already logged in, the system disables login on another machine.
As far as I am aware this functionality is not built in to Zend_Auth, but you could achieve what you want by extending the Zend_Auth_Adapter that you are currently using and overiding the authenticate() method as danielrsmith suggests.
You would need to add a table to your DB that is set/unset by the login process. The problem is going to be the unset if the user does not specifically log out, but you could store a timestamp in the DB and allow the login to expire for the next login attempt.
My_Auth_Adapter_DbTable extends Zend_Auth_Adapter_DbTable
{
public function authenticate()
{
$authResult = parent::authenticate();
if($this->alreadyLoggedIn(){
$authResult = new Zend_Auth_Result(
Zend_Auth_Result::FAILURE_UNCATEGORIZED,
$this->_identity,
array('User already logged in')
);
} else {
$this->setLoggedIn();
}
return $authResult;
}
private function alreadyLoggedIn()
{
//check db table to see if $this->_identity is already logged in
//then return true or false as appropriate
}
private function setLoggedIn()
{
//update table in DB to reflect logged in status
}
}
I haven't tested this code, but it will, hopefully, get you started in the right direction.
Also, doing it this way will, I think, avoid the need to alter the session handler in any way.
Try this:
Create session table in database:
CREATE TABLE session (
id char(32),
modified int,
lifetime int,
data text,
PRIMARY KEY (id)
);
Store session in database by Zend_Session_SaveHandler_DbTable. Put the following code in bootstrap.php
protected function _initDoctrineSession()
{
$url=constant("APPLICATION_PATH").DIRECTORY_SEPARATOR ."configs".DIRECTORY_SEPARATOR."application.ini";
$config=new Zend_Config_Ini($url,"mysql");
$db=Zend_Db::factory($config->db);
Zend_Db_Table_Abstract::setDefaultAdapter($db);
$config = array(
'name' => 'session',
'primary' => 'id',
'modifiedColumn' => 'modified',
'dataColumn' => 'data',
'lifetimeColumn' => 'lifetime'
);
Zend_Session::setSaveHandler(new Zend_Session_SaveHandler_DbTable($config));
Zend_Session::start();
}
When log in, save user id or user name in session:
$logged_user = new Zend_Session_Namespace('logged_user');
$logged_user->logged_user = $user->name;
Another log in deletes all expired sessions in database firstly:
$sessionModel = new Session();
$sessionModel->removeExpiredSessions();
5.After log in, search session table records to see if current user already logged in:
$sessions = $sessionModel->querySessions();
$flag=true;
foreach ($sessions as $session){
if(strpos($session['data'], $user->name)>0 and strpos($session['data'],"Zend_Auth")>0
){
$flag=false;
}
}
if($flag == false){
$this->_forward('index','index');
return;
}
This will work. But there is a problem, if a user closes the Web browser before log out, the user will not be able to log in again before the session expired. Anyone can help to fix the last problem?

How to create "remember me checkbox" using Codeigniter session library?

in Codeigniter I am building an Authentication system for my web site and to achieve that I use session library
session->set_userdata('username')
this will save the session -I believe- for some time
I want to provide a "remember me" checkbox in the login form so the user can save the session forever - could not find a way to save the session forever!?
Note:$sess_expiration will not work because it sets expiration date for all users and what I want to do is setting the expiration date based on his preferences
is that possible? and how to do it?
Thanks
If the remember me checkbox is checked you set a cookie on the user's system with a random string. E.g.:
$cookie = array(
'name' => 'remember_me_token',
'value' => 'Random string',
'expire' => '1209600', // Two weeks
'domain' => '.your_domain.com',
'path' => '/'
);
set_cookie($cookie);
You also save this random string in the users table, e.g. in the column remember_me_token.
Now, when a user (who is not yet logged in) tries to access a page that requires authentication:
you check if there is a cookie by the name of remember_me token on his system
if it's there, you check the database if there is a record with the same value
if so, you recreate this user's session (this means they are logged in)
show the page they were visiting
If one of the requirements above is not met, you redirect them to the login page.
For security reasons you may want to renew the random remember_me_token every time the user logs in. You can also update the expiry date of the cookie every time the user logs in. This way he will stay logged in.
It would be too much work to write all the code for you, but I hope this helps you to implement this functionality yourself. Please comment if you have any questions. Good luck.
I needed the same thing. You cannot accomplish this using CI settings so I have chosen to override the setcookie method of the CI Session class (in MY_Session):
function _set_cookie($cookie_data = NULL)
{
if (is_null($cookie_data))
{
$cookie_data = $this->userdata;
}
// Serialize the userdata for the cookie
$cookie_data = $this->_serialize($cookie_data);
if ($this->sess_encrypt_cookie == TRUE)
{
$cookie_data = $this->CI->encrypt->encode($cookie_data);
}
else
{
// if encryption is not used, we provide an md5 hash to prevent userside tampering
$cookie_data = $cookie_data.md5($cookie_data.$this->encryption_key);
}
setcookie(
$this->sess_cookie_name,
$cookie_data,
$this->userdata('rememberme') == true ? $this->sess_expiration + time() : 0,
$this->cookie_path,
$this->cookie_domain,
0
);
}
Of course you need to set the rememberme flag in your session based upon the choice the user made.
I used hooks to do this
Enable hooks in "config.php" setting $config['enable_hooks'] = TRUE;
In your login controller save the checkbox value on session
$this->session->set_userdata('remember_me', $this->input->post('remember_me'));
In your "hooks.php" file add this
$hook['post_controller_constructor'] = array(
'class' => 'Change_Config',
'function' => 'change_session_expiration',
'filename' => 'change_config.php',
'filepath' => 'hooks'
);
In your "hooks" folder create a file called "change_config.php" and paste this
<?php
class Change_Config {
public function change_session_expiration() {
$ci = & get_instance();
$remember = $ci->session->userdata('remember_me');
if($remember && $ci->session->sess_expire_on_close) {
$new_expiration = (60*60*24*365); //A year milliseconds
$ci->config->set_item('sess_expiration', $new_expiration);
$ci->config->set_item('sess_expire_on_close', FALSE);
$ci->session->sess_expiration = $new_expiration;
$ci->session->sess_expire_on_close = FALSE;
}
}
}
You could use isset to check if the cookie has a value, and if the cookie is deleted, it will return negative. If it is negative, you can set the cookie again... of course, this will be like "renewing" the cookie, so if the user doesn't come by the expiration, they will be forgotten. (Set a very big time till the expiration!)
For example:
<?php
if (isset($_COOKIE['autologin'])) { //Checks for cookie
echo "Welcome back!... Logging you in.";
}else{ //Sets a cookie
echo "Please sign in";
$expiretime=time()+60*60*24*365; //set expire time to a year
setcookie("autologin", "What is here is not important.", $expiretime);
};
?>
$this->session->sess_expiration = '14400'; // expires in 4 hours
$this->session->set_userdata($data); // set session
You can just put this
if ($remember) {
$new_expiration = (60*60*24*365);
$this->config->set_item('sess_expiration', $new_expiration);
$this->config->set_item('sess_expire_on_close', FALSE);
$this->session->sess_expiration = $new_expiration;
$this->session->sess_expire_on_close = FALSE;
}
You can set sess_expiration to 0 and then set a custom variable into the session like, remember_me=1. Check this value and destroy the session if needed after a time.
This would be a workarround.

Categories