I have this on my pages controller.
protected $auth = array();
function __construct(){
parent::__construct();
$this->auth['result'] = $this->is_logged_in();
}
and this is my core/base controller located at core folder.
public function is_logged_in(){
$session = $this->session->userdata();
if(isset($session['logged_in'])){
return $session;
}else{ return FALSE; }
}
Is the above codes enough? or am i missing something to do a legitimate authentication?(my first time trying to attempt a user authentication)
Also, would it be okay, if for example.
I added a column 'isLoggedin' on my accounts table.
int(1),NULL.
and whenever my login function is called and someone successfully logs in, i will also add a value to insert as 'isLoggedin' to 1. 1=true, 2=false.
So for example in my pages controller, since everytime it loads, it runs the is_logged_in() function in my base controller and would return the session data from there.
I would compare the returned session data from my base controller to the one in my accounts table with the 'isLoggedin' col set to 1.
OR
since the $auth data would return an 'id' then i would check the 'id' from $auth to any 'id' on the database where 'isLoggedin == 1'. If it matches with the 'id' from $auth.
$this->db->get_where('accounts', array('id' => $auth['id'], 'isLoggedin' => 1));
Related
I have a CodeIgniter 4 project.
When a user logins in and navigating through the website, at times the session()->get() will get a wrong session data thereby showing wrong user data because I use session to query user details from database.
This is how I set the session
$this->setUserSession($user);
private function setUserSession($user)
{
$data = [
'id' => $user['id'],
'username' => $user['username'],
'isLoggedIn' => true,
];
session()->set($data);
return true;
}
I call it using session()->get('id')
And I destroy it using
public function logout()
{
session()->destroy();
return redirect()->to('login');
}
Please How can I prevent the session from getting a wrong session data?
My registration form additionally accepts the name of the user's company, which I want to insert in a separate table "Holdings". All data is successfully saved to the Holdings and Users table, but an error occurs at the last step when redirecting to the home page.
ResgisterController:
protected function create(array $data)
{
//Mail::to($data['email'])->send(new Welcome($data['name']));
$id = User::insertGetId([
'name' => $data['name'],
'email' => $data['email'],
'password' => Hash::make($data['password']),
'role' => 8
]);
$oHolding = new Holdings;
$oHolding->shortname = $data['orgname'];
$oHolding->creator = $id;
$oHolding->save();
DB::table('users')->where('id', $id)->update([
'holding_id' => $oHolding->id,
]);
$user = DB::table('users')->select('*')->where('id', $id)->get();
return $user;
}
Error Message:
Argument 1 passed to Illuminate\Auth\SessionGuard::login() must implement interface Illuminate\Contracts\Auth\Authenticatable, instance of Illuminate\Support\Collection given, called in /Users/admin/Sites/jetime/vendor/laravel/framework/src/Illuminate/Foundation/Auth/RegistersUsers.php on line 35
Login Function
public function login(AuthenticatableContract $user, $remember = false)
{
$this->updateSession($user->getAuthIdentifier());
// If the user should be permanently "remembered" by the application we will
// queue a permanent cookie that contains the encrypted copy of the user
// identifier. We will then decrypt this later to retrieve the users.
if ($remember) {
$this->ensureRememberTokenIsSet($user);
$this->queueRecallerCookie($user);
}
// If we have an event dispatcher instance set we will fire an event so that
// any listeners will hook into the authentication events and run actions
// based on the login and logout events fired from the guard instances.
$this->fireLoginEvent($user, $remember);
$this->setUser($user);
}
I will be glad of any help, how to fix the error?
You are returning a collection rather than an instance of a class that implements Authenticatable.
You can see this happening here:
$user = DB::table('users')->select('*')->where('id', $id)->get();
return $user;
If you have the User model that ships with Laravel, then you'll actually want to do:
$user = User::find($id);
return $user;
Although your whole create method could be cleaned up to streamline all of this, however that isn't the topic of your question.
I am creating a small blog-esque site. This site has basically 3 permission levels: Admin (can edit/remove any post AND create a user), a user (can upload posts and pictures) and a guest (no account needed, can just browse the posts).
I am using Laravel 5.5 to create this site.
When someone logs in, after being authenticated, I store their username and user type (admin/user) in a session and after login, they are redirected to their respective pages, as shown in the below code.
I overrided the 'authenticated' method in the AuthenticatesUsers trait:
LoginController.php
protected function authenticated(Request $request, $user)
{
$type = $user->toArray()['type'];//get user type (admin/user)
$username = $user->toArray()['username'];
$request->session()->put('type', $type);
$request->session()->put('username', $username);
if ( $type == 'admin' ) {
return redirect()->route('admin_home');
}
return redirect()->route('user_home');
}
The above code works and my user is redirected upon successful login.
However, if my user accesses the site home (localhost:8000/) I want the user to see the admin home page or user home page (localhost:8000/ just shows the homepage for a not logged in guest)
I did that using the following codes:
Web.php
Route::get('/', 'ContentController#publicHome');
Route::middleware('auth')->group(function(){
Route::get('/user/home', 'ContentController#userHome')->name('user_home');
Route::get('/admin/home', 'ContentController#adminHome')->name('admin_home');
});
Filtering whether user is logged in or just a guest:
ContentController - publicHome function
public function publicHome(Request $request){
$data = [];
$data['home'] = 1;
if($request->session()->has('type')){
switch ($request->session()->pull('type')){
case 'admin':
return redirect()->route('admin_home');
case 'user':
return redirect()->route('user_home');
}
}
return view('public.home', $data);
}
ContentController - userHome function
public function userHome(Request $request){
$data = [];
$data['username'] = $this->getUsername($request);
$data['type'] = $this->getUserType($request);
// dd($data); explanation for this line below
return view('user.home', $data);
}
ContentController - adminHome function
public function adminHome(Request $request){
$data = [];
$data['username'] = $this->getUsername($request);
$data['type'] = $this->getUserType($request);
//dd($data);
return view('admin.home', $data);
}
ContentController - getUsername & getUserType functions
public function getUsername(Request $request){
return $request->session()->has('username') ? $request->session()->pull('username') : 'username not set';
}
public function getUserType(Request $request){
return $request->session()->has('type') ? $request->session()->pull('type') : 'user type not set';
}
I used the dump and die function to see the $data[] array before loading the view
Right after successful login:
array:2 [▼
"username" => "testAdmin"
"type" => "admin"
] //works correctly, session variables seem to be set
So when I type in localhost:8000/ I expect to be redirected to /admin/home (or /user/home depending on login) but I just get sent to localhost:8000/ as if I am not logged in. So now when I manually type in /admin/home I get the following dump and die output:
array:2 [▼
"username" => "username not set"
"type" => "user type not set"
]
If you are using $request->session()->pull('username') it fetches the data i.e. username from session and deletes it at the same time.
Instead, you can use laravel's helper method session() to get data without deleting it. So now you can use session('username') to get the username.
For more info refer : https://laravel.com/docs/5.5/session
Some Suggestions:
You could have used laravel's internal Auth library to build the login system which already has lot many features you don't need to code again. https://laravel.com/docs/5.5/authentication
You can also have multi-user authentication (admin & regular user). Refer this link if you want to implement so: https://scotch.io/tutorials/user-authorization-in-laravel-54-with-spatie-laravel-permission
I'm currently developing a restful/stateless api in cakephp which uses tokens (at the moment) and should use rolling tokens (like suggested here from g-shearer) in the future. My current implementation works, but i'm really concerned if i've implemented everything the right way (auth components especially custom auth components seem really confusing to me)
PS: I'm using the current version of cakephp (2.5.1).
1: I've created the file TokenAuthenticate.php in Controller/Component/Auth:
<?php
App::uses('BaseAuthenticate', 'Controller/Component/Auth');
class TokenAuthenticate extends BaseAuthenticate {
public function authenticate(CakeRequest $request, CakeResponse $response) {
}
public function getUser(CakeRequest $request) {
//set values from request headers
$publictoken = $request->header('Security-Public-Token');
$accesstoken = $request->header('Security-Access-Token');
$timestamp = $request->header('Security-Timestamp');
// check if required header fields are set
if (empty($publictoken) || empty($accesstoken) || empty($timestamp)) {
return false;
}
// init required token model
$Token = ClassRegistry::init('Token');
//check if token pair exists
if ($dbtoken = $Token->findByPublic($publictoken)) {
if ($accesstoken == md5($dbtoken['Token']['private'] . $timestamp)) {
//valid token - return user
$User = ClassRegistry::init('User');
$dbuser = $User->findById($dbtoken['Token']['user_id'])['User'];
return $dbuser;
} else {
//invalid token
return false;
}
} else {
//invalid token pair
return false;
}
}
public function unauthenticated(CakeRequest $request, CakeResponse $response) {
return true;
}
}
?>
then i've added the following to my controller:
class UsersController extends AppController {
public $uses = array('User', 'Token');
public $components = array('Auth' => array('authenticate' => array('Token')));
public function beforeFilter() {
parent::beforeFilter();
AuthComponent::$sessionKey = false;
$this->Auth->autoRedirect = false;
$this->Auth->allow('login', 'register');
}
in my actions i check the status like so:
if (!$this->Auth->loggedIn()) {
$this->set(array('error' => 'INVALID_AUTHENTIFICATION'));
$this->render('view');
}
So I can set a custom error and output it without being redirected to the login action (note the unauthenticated function in my tokenauthentication file which returns true - so cakephp does not redirect you)
I think the login process should happen in the authenticate function of my TokenAuthenticate file and not in the login action of my controller, or am i wrong? What is the correct way to achieve this goal?
PS: How would it be possible to add a new token pair (to every authenticated output) automatically with cakephp so the tokens are 'rolling'?
The whole api output is json encoded if that matters
also cakephp still sets a cookie sometimes even though i disabled this (AuthComponent::$sessionKey = false;). How to stop this?
EDIT: So I've added an beforeRender() function to my userscontroller and now the tokens are rolling (Y)
//renew tokens
public function beforeRender() {
//only add tokens if logged in
if ($this->Auth->loggedIn()) {
//find old token
$oldToken = $this->Token->findByUser_id($this->Auth->user('id'));
//delete old token
$this->Token->delete($oldToken['Token']['id']);
//create new token pair
$this->Token->create();
$this->Token->save(array(
'user_id' => $this->Auth->user('id'),
'public' => Security::hash(substr(str_shuffle('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!##$') , 0 , 15 )),
'private' => Security::hash(substr(str_shuffle('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!##$') , 0 , 15 ))
));
//set it for the view
$this->set(array('token' => $this->Token->read()));
}
}
Is this the right way to implement something like this? I always want to do things the right and 'perfect' way so any criticsm is welcome :)
I have yii project and in Chrome sessions is lost.
Example:
config in main.php
'session' => array(
'class' => 'CDbHttpSession',
'autoStart' => false,
'connectionID' => 'db',
'sessionTableName' => 'ph_YiiSession',
'autoCreateSessionTable' => false // for performance reasons
),
in start controller after login i write id user in session
Yii::app()->user->id = 100
after i redirect user
$this->redirect(array('student/index'), true);
but in index action i can't get data from session
echo Yii::app()->user->id;
give nothing. Please help, this problem crashed my brain already
You should try
'autoStart' => true,
Yii::app()->user->id = 100
First of all You can't set the Id like this permanently that could work in different pages. Even if you will set Id in a page, Its data will be lost as soon as you move to next page and it will show its default value. So if you want to change the value that Yii::app()->user->id contains then you will have to override getId() method.
Second Thing If you are trying to save the Id in the session then you should use Yii::app()->session['_myId']=Yii::app()->user->id;
and then you can get it like
echo Yii::app()->session['_myId'];
and remember 'autoStart' => TRUE,
What you are doing wrong is definitely in the UserIdentity class. The best method of setting and retrieving a session data from Yii::app()->user->id, is to override the getId() method in the UserIdentity class.
For example, lets say that you have a table named 'User' and it contains : id, username, password.
So, make the UserIdentity class something like this :
<?php
/**
* UserIdentity represents the data needed to identity a user.
* It contains the authentication method that checks if the provided
* data can identity the user.
*/
class UserIdentity extends CUserIdentity
{
private $_id;
public function authenticate()
{
$user = User::model()->find('LOWER(username)=?',array(strtolower($this->username)));
if($user===null){
$this->errorCode=self::ERROR_USERNAME_INVALID;
}else if($user->password !== crypt($this->password,$user->password)){
$this->errorCode = self::ERROR_PASSWORD_INVALID;
}
else{
$this->_id = $user->id;
$this->username = $user->username;
$this->errorCode = self::ERROR_NONE;
}
return $this->errorCode === self::ERROR_NONE;
}
public function getId()
{
return $this->_id;
}
}
Once you do this, you should be able to use the Yii::app()->user->id and get the session id anywhere in your code.
Hope this helped.
P.S > I have also made a base app where all this is already done. You may check it out at : https://github.com/sankalpsingha/yii-base-app it might help you.