I'm between a hard place and a rock with a CI problem. I have to dynamically connect to a DB with the username and password that users type. Those are their oracle usernames and passwords. So, with that information I have to do the connection to the DB and then keep it alibe for the different models and controllers within the application.
I have a login controller and a login view. I've disabled the database autoload from the database.php and config.php files.
Then, the login.php controller looks like this:
class Login extends CI_Controller {
public function index()
{
$this->output->enable_profiler(TRUE);
if (isset($_POST['ingresar'])){
$db['hostname'] = 'myhost';
$db['username'] = $_POST['usr'];
$db['password'] = $_POST['pwd'];
$db['database'] = 'DBname';
$db['dbdriver'] = 'oci8';
$db['dbprefix'] = '';
$db['pconnect'] = FALSE;
$db['db_debug'] = FALSE;
$db['cache_on'] = FALSE;
$db['cachedir'] = '';
$db['char_set'] = 'WE8ISO8859P1';
$db['dbcollat'] = '';
$db['swap_pre'] = '';
$db['autoinit'] = TRUE;
$db['stricton'] = FALSE;
$db['DB'] = $this->load->database($_SESSION, TRUE);
redirect('contactos', 'location');
}
else{
$this->load->view('/componentes/header');
$this->load->view('/componentes/menu_sin_login');
$this->load->view('/login/login');
$this->load->view('/componentes/footer');
}
}
When the controller redirects to the other controller "contactos" everything crashes because it doesn't recognize a database connection, on line 5, when trying to load a model.
class Contactos extends CI_Controller {
public function __construct()
{
parent::__construct();
$this->load->model('Contactos_model');
$this->load->model('Componentes_model');.....
Any help you can provide would be really appreciated.
Regards,
V
In the context above $db is a local variable, which means it doesn't really do anything about the broader context of the script, and you're not storing it anywhere that it could be re-used.
To load the DB, you probably want to call:
// you may want to think about using an encrypted CI session instead?
$_SESSION['DB'] = $db;
then, in contactos, you would want:
class Contactos extends CI_Controller {
public function __construct()
{
parent::__construct();
$this->load->database( $_SESSION['DB'] );
// continue as above.
Related
I understand that the title of the question may be vague but then that's the best way I could come up with to explain my issue at hand.
I'm overriding the OnActionExecuting function to manage my session related activities and allow/ deny requests to authorized/ unauthorized users, respectively. Along with tracking of the session, I'm also using the OnActionExecuting to load user available features for the current page into a temporary class and accessing from the view using ajax call.
namespace MyApp.Controllers
{
public class TESTController : Controller
{
[SessionTimeout]
public ActionResult Index()
{
return this.View();
}
}
}
public class SessionTimeoutAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
HttpContext ctx = HttpContext.Current;
if (ctx.Session["AppUser"] == null)
{
// Redirect to the login page
// Or deny request
}
else
{
var controllerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;
var actionName = filterContext.ActionDescriptor.ActionName;
var methodType = ((ReflectedActionDescriptor)filterContext.ActionDescriptor).MethodInfo.ReturnType;
if (methodType == typeof(ActionResult))
{
// Load all user access rights for the current page into a temporary memory
// by using the Action and Controller name
}
}
base.OnActionExecuting(filterContext);
}
}
The above works like a charm.. But the issue is when the user clicks on the back button of the browser or hits the backspace key. In that case, the OnActionExecuting function is never called for the ActionResult and further I am unable to load the current page access rights for the user.
Thanks & Regards,
Kshitij
Adding the following to my ActionResult made the above code to work.
[SessionTimeout]
[OutputCache(Duration = 0, NoStore = true)]
public ActionResult SomeView()
{
return this.View();
}
I'm trying to move to another database dynamically. I've seen several questions that showed change db files from one to another and they just getting some information from next database. But what I need is completely moving to second database. How should I do this? I've seen that in order to achieve this dsn (in db.php file) should be altered. But I changed it and it's still not changed?? I should have full access to second database closing first one. Give me advice please
Configs like db.php are not intended to be changed in process (while PHP is processing). They are loaded once in the initialization, when request is entered the framework.
As an alternative, you can configure second DB beforehand in db.php, and change between them dynamically like:
Yii::$app->db // your default Database
and
Yii::$app->db2 // Second configured Database, to which you can switch dynamically later
You can learn about multiple database connections here
So, if you want ActiveRecord(for instance User) to be able to access two databases, you can define some static variable, which specifies from which DB to read/write. For example:
class User extends \yii\db\ActiveRecord
{
const DB_DATABASE1 = 'db1';
const DB_DATABASE2 = 'db2';
private static $db = self::DB_DATABASE1;
public static function setDb($db)
{
self::$db = $db;
}
public static function getDb()
{
switch (self::$db) {
case self::DB_DATABASE1:
return Yii::$app->db;
case self::DB_DATABASE2:
return Yii::$app->db2;
default:
throw new \Exception("Database is not selected");
}
}
//...
And then use it in Controller like:
User::setDb(User::DB_DATABASE1);
$usersDB1 = User::find()->all();
User::setDb(User::DB_DATABASE2);
$usersDB2 = User::find()->all();
Set up multiple database connections in your main.php or main-local.php configuration
Yii::$app->db1;
Yii::$app->db2;
Yii::$app->db3;
when making inquiries
$usersDB1=User::find()->all(Yii::$app->db1);
$usersDB2=User::find()->all(Yii::$app->db2);
$usersDB3=User::find()->all(Yii::$app->db3);
Globally switch to a different database dynamically
I have combined Yerke's answer above and Write & use a custom Component in Yii2.0 here.
First, create a component class to do the DB switching. Here, I call it DbSelector and put it in app\components\DbSelector.php.
namespace app\components;
use Yii;
use yii\base\Component;
use yii\base\InvalidConfigException;
class DbSelector extends Component {
const DB_MAIN = 'db';
const DB_SUB1 = 'db1';
const DB_SUB2 = 'db2';
private static $db = self::DB_MAIN;
public static function setDb($db)
{
self::$db = $db;
}
public static function getDb()
{
return \Yii::$app->get(self::$db);
}
}
Second, modify the config/web.php file or whichever your config file is to have multiple databases and add DbSelector as a Yii::$app component.
$config = [
'components' => [
//...
'db' => $db,
'db1' => $db1,
'db2' => $db2,
'dbSelector' => [
'class' => 'app\components\DbSelector',
],
//...
],
//...
];
Third, in each model class, add the following static function getDb() to call the DbSelector getDb():
public static function getDb()
{
return \Yii::$app->dbSelector->getDb();
}
For example,
class DiningTable extends \yii\db\ActiveRecord
{
public static function tableName()
{
return '{{%dining_table}}';
}
public static function getDb()
{
return \Yii::$app->dbSelector->getDb();
}
//...
}
class Customer extends \yii\db\ActiveRecord
{
public static function tableName()
{
return '{{%customer}}';
}
public static function getDb()
{
return \Yii::$app->dbSelector->getDb();
}
//...
}
Lastly, to globally switch to a different database, use \Yii::$app->dbSelector->setDb(YOUR_PREFERRED_DB),
use app\components\DbSelector;
//...
\Yii::$app->dbSelector->setDb(DbSelector::DB_SUB1);
$tables_1 = DiningTable::findAll();
$customers_1 = Customer::find()->where(['<', 'dob', '2000-01-01'])->all();
\Yii::$app->dbSelector->setDb(DbSelector::DB_MAIN);
$tables_main = DiningTable::findAll();
$customers_main = Customer::find()->where(['<', 'dob', '2000-01-01'])->all();
This is a follow up question to my original question where I am trying to rehash user passwords during authentication to migrate from a legacy database.
After implementing the helpful answer there. I have now hit another problem where I receive no error (with the below code) but the passwords and salt are not being updated in the database:
security.yml
security:
encoders:
AppBundle\Entity\Member:
id: club.hub_authenticator
services.yml
services:
club.hub_authenticator:
class: AppBundle\Service\HubAuthenticator
arguments: ["#security.token_storage" ,"#club.password_rehash"]
club.password_rehash:
class: AppBundle\Service\PasswordRehash
arguments: [ "#security.token_storage" ]
HubAuthenticator.php
namespace AppBundle\Service;
use Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
class HubAuthenticator extends \Symfony\Component\Security\Core\Encoder\BCryptPasswordEncoder implements PasswordEncoderInterface
{
private $storage ;
private $passwordRehash ;
function __construct(TokenStorageInterface $storage, PasswordRehash $passwordRehash, $cost = 13)
{
parent::__construct($cost);
$this->storage=$storage ;
$this->passwordRehash = $passwordRehash;
}
function isPasswordValid($encoded, $raw, $salt)
{
// Test for legacy authentication (and conditionally rehash the password in the database)
if ($this->comparePasswords($encoded, sha1("SaltA".$raw."SaltB"))) {
$this->passwordRehash->rehash($raw);
return true ;
}
// Test for Bcrypt authentication
if (parent::isPasswordValid($encoded,$raw,$salt)) return true ;
}
}
PasswordRehash.php
namespace AppBundle\Service;
use Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
class PasswordRehash extends \Symfony\Component\Security\Core\Encoder\BCryptPasswordEncoder implements PasswordEncoderInterface
{
// private $storage ;
function __construct(TokenStorageInterface $storage , $cost = 13)
{
parent::__construct($cost);
// $this->storage=$storage ;
}
// Customises BCryptPasswordEncoder to use legacy Club SHA method
function rehash($raw)
{
// Commented out as I THINK the $raw is the plainPassword I'm trying to use to reencode the password
// $user=$this->storage->getToken()->getUser();
// $token = $this->storage->getToken();
//Salt left empty as have read this will auto-generate a new one (which is also better practice)
parent::encodePassword($raw, $salt=null ) ;
return true ;
}
}
If you want to store the result of PasswordRehash#rehash() as the value of your user's password, make your method returning the new password:
function rehash($raw)
{
return parent::encodePassword($raw, null);
}
Then, to update the user, you need to set the new password and store the changes.
Inject the doctrine EntityManager in your service:
club.hub_authenticator:
class: AppBundle\Service\HubAuthenticator
arguments: ["#security.token_storage" ,"#club.password_rehash", "#doctrine.orm.entity_manager" ]
And in your class:
use Doctrine\ORM\EntityManager;
function __construct(TokenStorageInterface $storage, PasswordRehash $passwordRehash, EntityManager $em, $cost = 13)
{
parent::__construct($cost);
$this->storage = $storage;
$this->passwordRehash = $passwordRehash;
$this->em = $em;
}
Then use it:
if (!$token = $this->storage->getToken()) {
return;
}
if ($this->comparePasswords($encoded, sha1("SaltA".$raw."SaltB"))) {
// Retrieve the user
$user = $token->getUser();
// Change the user password
$user->setPassword($this->passwordRehash->rehash($raw));
// Save the changes
$em->flush($user);
}
But, I'm really not sure about the logic you are implementing.
I don't see the benefit of extending the BcryptPasswordEncoder.
You should look at this post that shows a quick way to convert the password of your users from a legacy app to FOSUserBundle-compliant passwords in only one time, rather than do it on each authentication.
Then look more at how to work with services in Symfony2+.
Hope this helps you.
I have a form and I'm trying to login by using Laravels Auth method.
At the moment I have this snippet:
$input = Input::all();
$login = Auth::attempt([
'username' => $input['username'],
'password' => $input['password']
]);
if($login){
return "Logged in";
}
dd('problem');
But even after entering correct credentials I'm getting to see "problem"
in models/User.php I've changed my table name to tbl_login(like I have in the DB) and that is the only change I've made in it
and in my login model I have
class Login extends Eloquent {
protected $guarded = array();
protected $table = "tbl_login";
protected $primaryKey = "pk_loginID";
public static $rules = array();
}
I also checked this topic but didn't really help and I'm hoping that you guys can help me with this now.
Just as info and a sidenote: table name in Db = tbl_login
primary key field is pk_loginID
username field = username
password field = password
Did I forget something or did I do something wrong?
EDIT:
I've found the problem more specific, but not a solution for it. My password field in the DB has another name than the default password field that Laravel uses. How can I say to Laravel to use my custom password field?
I've found the solution
In the User model in the method getAuthPassword()
public function getAuthPassword()
{
return $this->attributes['passwordFieldinYourTable'];//change the 'passwordFieldinYourTable' with the name of your field in the table
}
That's it :)
You can't change it, but you probably can fix that by creating new mutators to the password field:
<?php
use Illuminate\Auth\UserInterface;
use Illuminate\Auth\Reminders\RemindableInterface;
class User extends Eloquent implements UserInterface, RemindableInterface {
...
public function getPasswordAttribute()
{
return $this->YourPasswordField;
}
public function setPasswordAttribute($password)
{
$this->YourPasswordField = $password;
}
}
I am adding an email validation step to my user registration. I cannot seem to get access to the arguments that are being passed in the emailed link;
link: activation.php?email=someone#somewhere.com&key=5614c46be05a95f55f2231d8dea41418d17b197a
Here is the page code;
class page_activation extends Page {
function init(){
parent::init();
if($this->api->auth->isLoggedIn())$this->api->redirect('index');
$loginAccount = $_GET['email'];
$activationKey = $_GET['key'];
$this->add('H1')->set('Activated');
$this->add('H3')->set('Account: '.$loginAccount);
$this->add('H3')->set('Key: '.$_GET['key']);
}
var_dump($_GET);
check network tab in inspector to make sure get params are actually passed.
check mod rewrite rules
I have found a solution in case it might help someone. It seems you can access the $_SERVER vars but the $_GET vars are lost by the time you get to the page. Here is some code that I used to accesses the passed vars from the email link;
class page_activation extends Page {
function init(){
parent::init();
if($this->api->auth->isLoggedIn())$this->api->redirect('index');
$data = parse_url($_SERVER['REQUEST_URI'], PHP_URL_QUERY);
$queryParts = split('[;&]', $data);
$params = array();
foreach ($queryParts as $param) {
$item = explode('=', $param);
$params[$item[0]] = $item[1];
}
$loginAccount = $params['email'];
$activationKey = $params['key'];
$this->add('H1')->set('Activated');
$this->add('H3')->set('Account: '.$loginAccount);
$this->add('H3')->set('Key: '.$activationKey);
}
}