Codeigniter 4 allow user to login using either username or email - codeigniter-4

Currently I have a login feature and I have only set user can login using username. How do I make it for user to login either using username or email and check with my database if username exist when users login with their username and if email exist when users login with their email? Below is my current code:
Controller
public function login()
{
$data = [];
helper(['form']);
$validation = \Config\Services::validation();
if($this->request->getMethod() == 'post'){
//validations
$rules = [
'username' => 'required',
'password' => 'required|validateUser[username, password]'
];
$errors = [
'password' => [
'validateUser' => 'Username or Password don\'t match'
]
];
if(!$this->validate($rules, $errors)){
$data['validation'] = $this->validator;
}else{
$model = new AccountModel();
$user = $model->where('username', $this->request->getVar('username'))
->first();
$this->setUserSession($user);
return redirect()->to('/account/profile');
}
}
echo view('templates/header', $data);
echo view('account/login');
echo view('templates/footer');
}
My validation rules
<?php
namespace App\Validation;
use App\Models\AccountModel;
class UserRules
{
public function validateUser(string $str, string $fields, array $data)
{
$model = new AccountModel();
$user = $model->where('username', $data['username'])
->first();
if(!$user)
return false;
return password_verify($data['password'], $user['password']);
}
}
?>
Thanks in advance guys!

First, the username and the email must be unique.
So, when the user enters an input either email or username
you can check if the user enters email using the following code
$email = $this->request->getPost('email');
if(substr_count($email , '#') > 0) // this is an email
check for the email if its exists in the database
else // not an email which means it is username
check for the username if its exists in the database
You can find this function substr_count()
Edit: You can use orWhere function so for example
$model->where('username' , $username)->orWhere('email',$email)->find()
so this will produce this statement
select * from tablename where username='' or email =''

In Codeigniter 4, there's a built in checker for email format validity and if email exists already in database without creating a database query. You just setup a Model and use the validations like
protected $validationRules = [
'username' => 'required|alpha_numeric_space|min_length[3]',
'email' => 'required|valid_email|is_unique[users.email]',
'password' => 'required|min_length[8]',
'pass_confirm' => 'required_with[password]|matches[password]'
];
more samples here, https://codeigniter.com/user_guide/models/model.html?highlight=valid_email

Related

Issue while trying to validation encrypted password in CodeIgniter 4

Creation of database record
$encrypter = \Config\Services::encrypter();
$password = base64_encode($encrypter->encrypt("12345aA!"));
$data = [
"email_address" => "email#gmail.com",
"password" => $password,
"user_id" => 1
];
$query = "insert into tblusers(user_id, email_address, password)";
$query = $query . "Values(:user_id,, :email_address, :password)";
$this->db->query($query, $data);
$this->db->table("tblusers")->insert($data);
Validation of Password with database saved record
$encrypter = \Config\Services::encrypter();
$model = new UserModel();
$user = $model->where("email_address", "email#gmail.com")->first();
echo $encrypter->decrypt($user["password"]);
Approach 2 used but same error message comes
$encrypted_password = "Py02s1SOIlI/p6sSzqDCqgR81wXuXSSdrA5R8wnLs/SQDig0A2hXjvcn4TfYYaa+Xoq4sMt4gJF5Krec8U8G8fKcrrXsSxbSG3BS";
echo $encrypter->decrypt($encrypted_password);
Error Message
Decrypting: authentication failed.
It is because you're applying base64_encode(...) after encrypting your 'raw password'.
// ...
$password = base64_encode($encrypter->encrypt("12345aA!"));
// ...
But then, you forget to apply base64_decode(...) before decrypting the stored 'password hash'.
// ...
echo $encrypter->decrypt($user["password"]);
// ...
Solution:
Validation of Password with database saved record
$model = new UserModel();
$user = $model->where("email_address", "email#gmail.com")->first();
try {
$decryptedPassword = \Config\Services::encrypter()
->decrypt(base64_decode($user["password"]));
echo $decryptedPassword;
} catch (\CodeIgniter\Encryption\Exceptions\EncryptionException $encryptionException) {
log_message("error", $encryptionException->getMessage());
}
Extra Note(s):
I would recommend you use PHP's built-in secure hashing algorithms instead for this scenario.
password_hash(...)
password_verify(...)

Login to many context in modx using api functions

I am working in facebook login, after successful facebook authentication i want to login user using modx api, i am able to login him using below code. But i am not getting how to login to multiple contexts, i tried to pass "login_context" parameter but still it only login him in "web" context and not other contexts.
$c = array(
'login_context' => 'tech,data,finance',
'username' => $username,
'password' => $password,
'returnUrl' => 'http://www.mydomain.com',
);
$response = $modx->runProcessor('security/login', $c);
loginContext its for only one context, if you need to login to multiple contexts - use add_contexts option.
This is just basic code to give you simple idea how it can be done.
if(isset($_POST) && count($_POST)){
$username = $_POST['uname'];
$password = $_POST['upass'];
$c = array(
'login_context' => 'web', // main context
'add_contexts' => 'profile,gallery,videos', // other contexts
'username' => $username,
'password' => $password
);
$response = $modx->runProcessor('security/login',$c);
if($response){
if (!$response->isError()) {
if($response->response['success'] == 1){
echo json_encode(array("success"=>1));
}else{
echo json_encode($response->response);
}
}else{
echo json_encode($response->response);
}
}
}

Kohana auth model

I'm new to kohana 3.2 and i couldnt find any answer regrading the auth module.
this is my code and forsome reason ever since i changed the user model to extend model_auth_user
the validation isnt being done prooperly. The password field can be inserted empty and no excpetion will be caught and same if the password_confirm and password fields are different:
public function action_new()
{
if ($_POST){
try
{
$user = ORM::factory('user')
->values(array(
'username' => $_POST['username'],
'email' => $_POST['email'],
'password' => $_POST['password'],
'password_confirm' => $_POST['password_confirm']));
$user->save();
$user->add('roles', ORM::factory('role', array('name' => 'login')));
$this->request->redirect('user/index');
}
catch (ORM_Validation_Exception $e)
{
$errors = $e->errors();
}
}
$view = View::factory('user/new')
->bind('errors',$errors); //pass the info to the view
$this->response->body($view); //show the view
}
thanks
You can override run_filter() method to force Kohana ignore password filtering in case of empty value. For example, put this code to your User_Model:
protected function run_filter($field, $value)
{
if ($field === "password" AND $value === "")
return "";
parent::run_filter($field, $value);
}
Try code sample from Model_Auth_User::create_user();
$user->save(Model_User::get_password_validation($_POST)->rule('password', 'not_empty'));
This validation execute before filters(hashing password). After hashing - blank password becomes not empty string.

login to modx from external/other server revolution 2.2.5

I am pissed off with this problem from 2 days.
I am using MODx Revolution 2.2.5 (traditional) and want to login to modx from external server just to fetch some user details.
1) I know that runprocessor method works only if i am logged in to manager (unfortunately, that's the only way i know to login user in) So i tried IFRAME method to avoid (cross scripting) it worked perfectly but i am not able to read the data from IFRAME using javascript because of same issue, cross domain access policy.
When i try to post data using some other method like CURL, Ajax using
header("Access-Control-Allow-Origin: *");
I am able to login (I see $response->response['success'] == 1) but cant access any data and it says
Fatal error: Call to a member function get() on a non-object
Below is the snippet code i am using
if(isset($_POST) && count($_POST)){
$c = array(
'username' => $_POST['username'],
'password' => $_POST['password']
);
$response = $modx->runProcessor('security/login',$c);
if($response->response['success'] == 1){
$user['id'] = $modx->user->get('id');
$profile = $modx->user->getOne('Profile');
$user['fullname'] = $profile->get('fullname');
$user['email'] = $profile->get('email');
echo json_encode($user);
}else{
echo json_encode($response->response);
}
}
2) I can use login snippet but it doesnt return output what i expect. We have ready site and we are already using login plugin so i cant even modify login plugin to respond with expected data
How can i login to modx using api or any other method ??
You are really attacking this problem completely wrong in my opinion. If you want to access a server/webpage from another, you don't iFrame and do it the way you are. That is hacking, and this hole will most likely be fixed in a future version.
What you SHOULD do is connecting to the database and just gather the information from the user-table.
No hacking, no "tricks", won't stop working and much safer.
Well, I sorted out this today, Below is the complete come that worked perfectly.
Pay attention to
header("Access-Control-Allow-Origin: http://www.xyz.com");
Using above CORS specification you can allow 2 servers to communication.
header("Access-Control-Allow-Origin: http://www.xyz.com");
if(isset($_POST['username']) && isset($_POST['password'])){
// get username and password from POST array
$username = $modx->sanitizeString($_POST['username']);
$password = $modx->sanitizeString($_POST['password']);
if(trim($username) != "" and trim($password) != ""){
// Load lexicons to show proper error messages
if (!isset($modx->lexicon) || !is_object($modx->lexicon)) {
$modx->getService('lexicon','modLexicon');
}
$modx->lexicon->load('login');
$loginContext= isset ($scriptProperties['login_context']) ? $scriptProperties['login_context'] :
$modx->context->get('key');
$addContexts= isset ($scriptProperties['add_contexts']) && !empty($scriptProperties['add_contexts']) ? explode(',', $scriptProperties['add_contexts']) : array();
$mgrEvents = ($loginContext == 'mgr');
$givenPassword = $password;
/** #var $user modUser */
$user= $modx->getObjectGraph('modUser', '{"Profile":{},"UserSettings":{}}', array ('modUser.username' => $username));
if (!$user) {
$ru = $modx->invokeEvent("OnUserNotFound", array(
'user' => &$user,
'username' => $username,
'password' => $password,
'attributes' => array(
'loginContext' => $loginContext,
)
));
if (!empty($ru)) {
foreach ($ru as $obj) {
if (is_object($obj) && $obj instanceof modUser) {
$user = $obj;
break;
}
}
}
if (!is_object($user) || !($user instanceof modUser)) {
//echo "cant locate account";
echo $modx->toJSON($modx->error->failure($modx->lexicon('login_cannot_locate_account')));
exit;
}
}
if (!$user->get('active')) {
//echo "inactivated accout";
echo $modx->toJSON($modx->error->failure($modx->lexicon('login_user_inactive')));
exit;
}
if (!$user->passwordMatches($givenPassword)) {
if (!array_key_exists('login_failed', $_SESSION)) {
$_SESSION['login_failed'] = 0;
}
if ($_SESSION['login_failed'] == 0) {
$flc = ((integer) $user->Profile->get('failedlogincount')) + 1;
$user->Profile->set('failedlogincount', $flc);
$user->Profile->save();
$_SESSION['login_failed']++;
} else {
$_SESSION['login_failed'] = 0;
}
//echo "wrong username pass";
echo $modx->toJSON($modx->error->failure($modx->lexicon('login_username_password_incorrect')));
exit;
}
$fullname = $user->Profile->get('fullname');
echo '{"success":true,"message":"Welcome '.$fullname.'!"}';
}else{
echo '{"success":false,"message":"Please enter username and password"}';
}
}

drupal 6 programmatically log user in

I'm trying to log in a user as part of a form submit, but why is the following not working:
$user = db_fetch_object(db_query("SELECT * FROM users WHERE mail = '%s' AND pass = '%s'", $mail, md5($pass)));
if ($user) {
// Authenticate user and log in
$params = array(
'name' => $user->name,
'pass' => trim($user->pass)
);
// Authenticate user
$account = user_authenticate($params);
}
if I dump $user I can see the correct values, but if I dump the account it's empty.
You are passing the hashed password to ´user_authenticate()´, while the function expects the clear password (it will hash it itself indirectly when loading the account via ´user_load()´).
So changing your $params array declaration to
$params = array(
'name' => $user->name,
'pass' => $pass
);
should make your example work.
BTW, you could use user_load() yourself to avoid querying the database directly:
$user = user_load(array('mail' => $mail, 'pass' => trim($pass), 'status' => 1));
(The 'status' => 1 will restrict results to active users - you can leave that out, of course, if you really want to allow log ins to disabled accounts ;)

Resources