i am trying to get my head around sessions and how to use them to show user data and grant access to areas of the site etc...
i have session_start(); at the beginning of my config file, then proceed to do the connection to database etc...
i then have a User.php class which is as follows:
<?php
include('Password.php');
class User extends Password{
private $db;
function __construct($db){
parent::__construct();
$this->_db = $db;
}
public function is_logged_in(){
if(isset($_SESSION['loggedin']) && $_SESSION['loggedin'] == true){
return true;
}
}
private function get_user_hash($username){
try {
$stmt = $this->_db->prepare('SELECT password FROM members WHERE username = :username');
$stmt->execute(array('username' => $username));
$row = $stmt->fetch();
return $row['password'];
} catch(PDOException $e) {
echo '<p class="error">'.$e->getMessage().'</p>';
}
}
public function login($username,$password){
$hashed = $this->get_user_hash($username);
if($this->password_verify($password,$hashed) == 1){
$_SESSION['loggedin'] = true;
return true;
}
}
public function logout(){
session_destroy();
}
}
?>
which when i use var_dump($_SESSION); returns:
array(1) { ["loggedin"]=> bool(true) }
what i am wanting to do is have things like "Hello, '(persons username)' welcome to the '(basic,premium,admin etc...)' area of the site".
so i think i want to be doing things like $_SESSION['memberID'], $_SESSION['username'], $_SESSION['level']
so... first of all am i looking at the right area to do this kind of thing (User.php) and would modifying anything i already have allow me to do this, or do i need to create another function(s) and query the database etc... if i do things like $_SESSION['username'] = 'mee'; then it will display 'mee', but what i am wanting to do is get the username for whichever user is logged in.
*apologies in advance if this makes little sense or is confusing, iv been trying to figure this out for some time now and literally nothing im doing makes sense - brain overload :/
For security purposes it is prudent to query the database for every subsequent request to restricted areas in your application. This can be achieved by simply storing the user id in the session variable and pulling the user data with every request by the stored user id. This way if access is revoked while the user is still logged in the system will respond correctly
This functionality could be achieved like so:
// after successfully getting user by the provided username/password
$_SESSION['logged_in_user_id'] = $user['id']
Now, on every request you simply check:
if (isset($_SESSION['logged_in_user_id'])) {
$currentUser = (new User())->find($_SESSION['logged_in_user_id']);
}
In your user model you could do something like this:
public function find($id) {
try {
$stmt = $this->_db->prepare('SELECT name, address, user_level, email FROM members WHERE id = :id');
$stmt->execute(array('id' => $id));
$row = $stmt->fetchAll();
$user = new self();
$user->fill($row[0]);
return $user;
} catch(PDOException $e) {
echo '<p class="error">'.$e->getMessage().'</p>';
} catch (Exception $e) {}
return null;
}
public function fill(array $data) {
foreach ($data as $key => $value) {
$this->$key = $value;
}
return $this;
}
To log the user out:
unset($_SESSION['logged_in_user_id']);
This method has the added benefit of keeping sensitive user data out of the plain text session files on your server which could be read by anyone with access to the box.
Now, with sessions you do need to keep in mind the potential for session hijacking but that is another discussion and there are tons of PHP packages out there to help protected against this vulnerability.
If you are not concerned with security and just want to get it working with as little effort as possible (not recommended) you can simply store the user data array in the session and use whatever you need from it:
Log in code:
public function login($username,$password){
if ($user = $this->getWithCredentials($username, $password) {
$_SESSION['logged_in_user'] = json_encode($user);
return true;
}
return false;
}
public function getWithCredentials($username, $password) {
try {
$hashedPassword = $this->myPasswordHashAlgorithm($password);
$stmt = $this->_db->prepare('SELECT id, name, address, email FROM members WHERE username = :username AND password = :password');
$stmt->execute(array('username' => $username, 'password' => $hashedPassword));
$row = $stmt->fetch();
return $row;
} catch(PDOException $e) {
echo '<p class="error">'.$e->getMessage().'</p>';
} catch (Exception $e) {}
return null;
}
Then, to get user data on subsequent requests:
$user = isset($_SESSION['logged_in_user']) ? json_decode($_SESSION['logged_in_user'] : null;
Related
So I am dealing with merging in functionality for rehashing to upgrade users to have bcrypt passwords, into a existing class I found and have set up quite successfully, its wonderful.
However, this class lacks rehashing check, which is terrible for legacy passwords on existing user databases. We need to handle SHA1 passwords! We use SHA1 + Salt, so I hope this is possible to convert.
Im using this class found here:
https://alexwebdevelop.com/user-authentication/
So using this class, I have added the following public function:
public function authenticate($username, $password)
{
/* Global $pdo object */
global $pdo;
// Database lookup
$stmt = $pdo->prepare("SELECT id, password, legacy_password FROM users WHERE username = ?");
$stmt->execute([$username]);
$stored = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$stored) {
// No such user, throw an exception
throw new Exception('Invalid user.');
}
if ($stored['legacy_password']) {
// This is the legacy password upgrade code
if (password_verify(sha1($password), $stored['password'])) {
$newHash = password_hash($password, PASSWORD_DEFAULT);
$stmt = $pdo->prepare("UPDATE users SET password = ?, legacy_password = FALSE WHERE id = ?");
$stmt->execute([$newhash, $stored['id']]);
// Return the user ID (integer)
return $stored['id'];
}
} elseif (password_verify($password, $stored['password'])) {
// This is the general purpose upgrade code e.g. if a future version of PHP upgrades to Argon2
if (password_needs_rehash($stored['password'], PASSWORD_DEFAULT)) {
$newhash = password_hash($password, PASSWORD_BCRYPT);
$stmt = $pdo->prepare("UPDATE users SET password = ? WHERE id = ?");
$stmt->execute([$newhash, $stored['id']]);
}
// Return the user ID (integer)
return $stored['id'];
}
// When all else fails, throw an exception
throw new Exception('Rehashing failed.');
}
Now inside the login() function of the class, I have replaced
public function login($name, $passwd)
{
...
if (is_array($row)) {
if (password_verify($passwd, $row['password'])) {
/* Authentication succeeded. Set the class properties (id and name) */
$this->id = intval($row['id'], 10);
$this->name = $name;
$this->authenticated = TRUE;
/* Register the current Sessions on the database */
$this->registerLoginSession();
/* Finally, Return TRUE */
return TRUE;
}
}
}
With this:
public function login($name, $passwd)
{
...
if (is_array($row)) {
$userid = $this->authenticate($name, $row['password']);
if (password_verify($passwd, $row['password'])) {
/* Authentication succeeded. Set the class properties (id and name) */
$this->id = intval($userid);
$this->name = $name;
$this->authenticated = TRUE;
/* Register the current Sessions on the database */
$this->registerLoginSession();
/* Finally, Return TRUE */
return TRUE;
}
}
}
And so it is supposed to return the hand back the ID after check / rehashing. So it finds me as a user, as tested. Good.. so now all authenticate() does is throw exception error of failure. I can't figure out how to get error messages out of this.
This seems like this the exact thing to do with this ID, what am I doing wrong?
This point of this: User logs in with SHA1 (salted) password in form, script rehashes password, and user logs in like nothing happened.
authenticate() conversion function I'm using:
https://paragonie.com/blog/2016/02/how-safely-store-password-in-2016#legacy-hashes
Im so sorry! I have learned from the suggestions here and I appreciate all the help!
So I solved this myself. What I did was remove authenticate() function, and instead tackled this directly based on the feedback comments (I couldn't agree more).
I replaced the last code block in the post, with this:
if (is_array($row)) {
if (password_needs_rehash($row['password'], PASSWORD_DEFAULT)) {
$newhash = password_hash($passwd, PASSWORD_BCRYPT);
$stmt = $pdo->prepare("UPDATE users SET password = ? WHERE id = ?");
$stmt->execute([$newhash, $row['id']]);
}
if (password_verify($passwd, $row['password'])) {
/* Authentication succeeded. Set the class properties (id and name) */
$this->id = intval($row['id'], 10);
$this->name = $name;
$this->authenticated = TRUE;
/* Register the current Sessions on the database */
$this->registerLoginSession();
/* Finally, Return TRUE */
return TRUE;
}
}
And users passwords are rehashing, and logging in!
I have a problem with my script. I have been using this same script for months. Lat week I got a message from my client that cannot access their
dashboard anymore. I check it was showing too much redirect problem. I
quickly made attempt to solve this programming but all availed. I found out
that the session actually set on the Login page because I echo it out
without redirecting, but whenever I redirect to member dashboard the session
variable will be undefined. I have gone through other people similar problem
on this forum but none were able to proffer solution to my problem. Because
this same script has been working for months. Please take a look at the code
and help me out.
This is Login page. Login.php The session actually set because when display LoginId when I echo echo it out. but lost when redirecting to another page. though It was working for more four months before this unexpected problem
<?php
require("includes/config.php");
require_once(ROOT_PATH . "main/class.member.php");
$auth_member = new MEMBER();
if($auth_member->is_loggedin() != ""){
$auth_member->redirect(BASE_URL.'member');
}
if(isset($_POST['loginMemBtn'])){
$userLoginID = strip_tags($_POST['userID']);
$password = strip_tags($_POST['password']);
if($auth_member->memberLogin($userLoginID, $password)){
$auth_member->redirect(BASE_URL.'member');
}
else{
$error[] = "Inccorrect Login Details!";
}
}
?>
class.member.php
This is the class that holds all the member details and where the session
was set. It contain MemberLogin Function
<?php
session_start();
error_reporting(E_ALL);
ini_set('display_errors', '1');
require_once(ROOT_PATH.'includes/dbconnect.php');
// Class
class MEMBER{
private $connect;
public function __construct(){
$database = new Database();
$db = $database->dbConnection();
$this->connect = $db;
}
public function lastInsertId(){
return $this->connect->lastInsertId();
}
public function runQuery($sql){
$stmt = $this->connect->prepare($sql);
return $stmt;
}
public function memberLogin($userLoginID, $password){
try {
$stmt = $this->connect->prepare("SELECT * FROM members
WHERE status='Active'
AND (email=:email OR phone=:phone OR username=:email)
");
$stmt->execute(array(':email'=>$userLoginID, ':phone'=>$userLoginID));
$userRow=$stmt->fetch(PDO::FETCH_ASSOC);
if($stmt->rowCount() > 0) {
if(password_verify($password, $userRow['password'])) {
$_SESSION['member_session'] = $userRow['login_id'];
return true;
}else{
return false;
}
}
}
catch(PDOException $e){
echo $e->getMessage();
}
}
public function is_allowuser(){
if(isset($_SESSION['member_session'])) {
return true;
}
}
public function redirect($url){
header("Location: $url");
}
public function doMememberLogout(){
session_destroy();
unset($_SESSION['member_session']);
return true;
}
}
?>
session.php this file that check whether session is set or not and it
include i to all other script
<?php
$session = new MEMBER();
if(!$session->is_allowuser()){
$session->redirect(BASE_URL.'login');
exit();
}else{
$auth_member = new MEMBER();
$loginID = $_SESSION['member_session'];
$stmt = $auth_member->runQuery("SELECT * FROM members WHERE
login_id=:loginID");
$stmt->execute(array(":loginID"=>$loginID));
$userInfo = $stmt->fetch(PDO::FETCH_ASSOC);
if($userInfo['status'] != 'Active'){
unset($_SESSION['member_session']);
}
}
?>
This is dashboard.php this is the page that member redirect to from Login
Page
<?php
require("../includes/config.php");
require_once(ROOT_PATH . "main/class.member.php");
require_once(ROOT_PATH . "main/session.php");
//echo $_SESSION['member_session'];
?>
public function redirect($url){
header("Location: $url");
exit;
}
Use exit after header call in redirect method of class.member.php file
Hey guys I have a question and I still consider myself pretty new at coding, so forgive me if I come off foolish.
I am studying in school as of now and we have a project to build a full stack recreation of craigslist. Any who the problem I am having deals with PHP. I have created an account page with text areas. I would like to echo out the user's information on their so the user can see what he put on and update as he likes. Since my navbar is included on every page, I added the code:
if(isset($_SESSION['logged_in_user'])){
var_dump($_SESSION['logged_in_user']);
$user = $_SESSION['logged_in_user'];
var_dump($user);
}
on my account page I figured I can echo it out as
<?= $attributes['first_name']?> within the placeholders. But I keep getting:
Undefined index: first_name
Also when I var_dump($user) I get an protected $attributes array.
In My Auth class is where I first defined $user as such:
public static function attempt($attemptedUsername, $attemptedPassword) {
$user = User::findByUserName($attemptedUsername);
if ($user == null) {
return false;
}
$validPassword = password_verify($attemptedPassword,$user->password);
if ($validPassword == true) {
$_SESSION['logged_in_user'] = $user;
}
return false;
}
and my findByUserName function is in the user class. the code is:
public static function findByUserName($user_name){
// Get connection to the database
self::dbConnect();
$stmt = self::$dbc->prepare('SELECT * FROM users WHERE user_name = :user_name');
$stmt->bindValue(':user_name', $user_name , PDO::PARAM_STR);
//execute gets its own line, t or false
$stmt->execute();
$result=$stmt->fetch(PDO::FETCH_ASSOC);
// #TODO: Create select statement using prepared statements
// #TODO: Store the result in a variable named $result
// The following code will set the attributes on the calling object based on the result variable's contents
$instance = null;
if ($result) {
$instance = new static($result);
}
return $instance;
}
Your problem seems to be with not being able to access the variable $user outside of the static method attempt() this can be fixed by declaring the variable globally at the beginning of the method attempt() like this:
public static function attempt($attemptedUsername, $attemptedPassword) {
global $user;
$user = User::findByUserName($attemptedUsername);
if ($user == null) {
return false;
}
$validPassword = password_verify($attemptedPassword,$user->password);
if ($validPassword == true) {
$_SESSION['logged_in_user'] = $user;
}
return false;
}
More information can be found on this in the PHP documentation here.
I'm in the process of learning how to use the CI framework and am currently working on a user login form. Haven't created a user registration yet, so I'm manually adding credentials into the database. Since I'm testing everything locally, I decided to give crypt a try with no salt which is probably not the best method. I'm using form validation and a callback to check the form data against the information in the database.
here is a snippet from the users controller:
function password_check($password) {
$username = $this->input->post('username', TRUE);
$password = Modules::run('security/create_hash', $password);
$this->load->model('mdl_users');
$result = $this->mdl_users->password_check($username, $password);
if ($result == FALSE) {
//$this->form_validation->set_message('password_check', 'Please login using the correct credentials!');
//return FALSE;
echo $password;
echo '<br/><br/>';
echo $result;
echo '<br/><br/>';
}
else {
return TRUE;
}
}
I echoed the password and the result for testing and password is showing as hashed.
Here is the password_check method:
function password_check($username, $password) {
$table = $this->get_table();
$this->db->where('username', $username);
$this->db->where('password', $password);
$query=$this->db->get($table);
$num_rows = $query->num_rows();
return $num_rows;
if ($num_rows>0) {
return TRUE;
} else {
return FALSE;
}
}
I'm sure the reason this isn't working is because the password in the DB is being treated as a literal string and not as hashed, but I'm not sure as to how I can compare it as a hash.
You could do something like this: get the user from the model and then check the saved value from the password with the hashed value from the user. If you would use md5 it would look a bit like this.
controller
$this->load->model('user_model');
public function login() {
$name = $this->input->post('name');
$password = $this->input->post('password');
$user = $this->user_model->get_user_through_name($name);
if($user['password'] == md5($password)) {
//logged in
} else {
//wrong password
}
}
model
public function get_user_through_name($name) {
$query = $this->db->get_where('Users', array(
'username' => $name
));
return $query->row_array();
}
Method in my class does it work properly. Don't give me some error message, but simply does not work.
public function query($value)
{
$this->__error = FALSE;
$sql = "SELECT * FROM users WHERE username = ".Input::input($value);
if ($this->__query = $this->__pdo->query($sql))
{
$this->__result = $this->__query->fetchAll(PDO::FETCH_OBJ);
$this->__count = $this->__query->rowCount(); //Here is the problem
}
else {
$this->__error = TRUE;
}
return $this;
}
public function count()
{
return $this->__count;
}
But I would not write whole class code, I mention that PDO DataBase connection is properly defined ($_pdo property), also the instance who is responsible to comunicate with database. ($_instance property). Input class too.
Here is my index.php (some kind of registration form):
<?php
spl_autoload_register(function($class) //Load all class in project
{
require_once 'class/'.$class.'.php';
}
);
$user = DataBase_class::instance()->query("username"); //username is the name of textbox
if ($user->count())
{
echo 'User exist';
}
else echo 'User not exist';
?>
Result is "User not exist", although user exist 100%.
You forget the quotes
$sql = "SELECT * FROM users WHERE username = '".Input::input($value) . "'";
but you should consider to use prepared statements..
$stmt = $this->__pdo->prepare("SELECT * FROM users WHERE username = :name");
$stmt->bindParam(':name', Input::input($value));
$result = $stmt->execute();