I have the following class. But when I try to access the Yii::app()->user->realName; it generates an error.
I can't understand it all. please help!
Following code is the code of my UserIdentity class.
<?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 {
public $id, $dmail, $real_name;
/**
* Authenticates a user.
* The example implementation makes sure if the username and password
* are both 'demo'.
* In practical applications, this should be changed to authenticate
* against some persistent user identity storage (e.g. database).
* #return boolean whether authentication succeeds.
*/
public function authenticate() {
$theUser = User::model()->findByAttributes(array(
'email' => $this->username,
// 'password' => $this->password
));
if ($theUser == null) {
$this->errorCode = self::ERROR_PASSWORD_INVALID;
} else {
$this->id = $theUser->id;
$this->setState('uid', $this->id);
// echo $users->name; exit;
// $this->setState('userName', $theUser->name);
$this->setState("realName",$theUser->fname .' '. $theUser->lname);
$this->errorCode = self::ERROR_NONE;
}
return!$this->errorCode;
}
}
?>
You need to extend the CWebUser class to achieve the results you want.
class WebUser extends CWebUser{
protected $_realName = 'wu_default';
public function getRealName(){
$realName = Yii::app()->user->getState('realName');
return (null!==$realName)?$realName:$this->_realName;
}
public function setRealName($value){
Yii::app()->user->setState('realName', $value);
}
}
You can then assign and recall the realName attribute by using Yii::app()->user->realName.
The protected $_realName is optional, but allows you to define a default value. If you choose not to use it, change the return line of the getRealName method to return $realName.
Place the above class in components/WebUser.php, or anywhere that it will be loaded or autoloaded.
Change your config file to use your new WebUser class and you should be all set.
'components'=>
'user'=>array(
'class'=>'WebUser',
),
...
),
Related
I need to authenticate my WebDriver Client for functional tests.
For example,
In my integration tests, i'm doing something like that :
namespace Tests\Controller;
use App\Entity\Donor;
use App\Entity\User;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Tools\SchemaTool;
use SebastianBergmann\Type\RuntimeException;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
class DonorTest extends WebTestCase
{
private static $client;
/**
* #var EntityManager
*/
private $entityManager;
/**
* #var SchemaTool
*/
private $schemaTool;
public function __construct(?string $name = null, array $data = [], string $dataName = '')
{
parent::__construct($name, $data, $dataName);
static::ensureKernelShutdown();
if (!self::$client) {
self::$client = static::createClient([], [
'PHP_AUTH_USER' => 'Same Old User',
'PHP_AUTH_PW' => 'Same Old Password',
]);
}
$this->entityManager = self::bootKernel()
->getContainer()
->get('doctrine')
->getManager();
$this->schemaTool = new SchemaTool($this->entityManager);
/** Safeguard */
$connection = $this->entityManager->getConnection()->getParams();
if ($connection['driver'] != 'pdo_sqlite' || $connection['path'] != '/tmp/test_db.sqlite') {
throw new RuntimeException('Wrong database, darling ! Please set-up your testing database correctly. See /config/packages/test/doctrine.yaml and /tests/README.md');
}
}
I'm just passing the credentials in paramaters, and it works.
But, in my functional tests, i'm using the WebDriver. It didn't accept credentials in arguments :
<?php
namespace App\Tests\Functional\Entities\Donor;
use App\Entity\Donor;
use App\Tests\Functional\Helpers\Carrier\CarrierHelper;
use App\Tests\Functional\Helpers\Donor\DonorHelper;
use Doctrine\ORM\EntityManager;
use Facebook\WebDriver\WebDriverBy;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Panther\PantherTestCase;
use Symfony\Component\Panther\Client;
class DonorTest extends PantherTestCase
{
/**
* #var EntityManager
*/
private $entityManager;
/**
* #var CarrierHelper
*/
private $helper;
/**
* #var Client
*/
private $client;
public function __construct(?string $name = null, array $data = [], string $dataName = '')
{
parent::__construct($name, $data, $dataName);
$this->entityManager = self::bootKernel()
->getContainer()
->get('doctrine')
->getManager();
$this->helper = new DonorHelper();
}
public static function setUpBeforeClass(): void
{
// Do something
}
public function setUp(): void
{
parent::setUp(); // TODO: Change the autogenerated stub
$this->client = Client::createChromeClient();
$this->client->manage()->window()->maximize();
}
I can't pass any login arguments in createChromeClient() method.
I think i have to play with cookies in cookieJar, or token, but i don't know how.
Feel free to ask me my ahtentication method, but i've followed the documentation :
https://symfony.com/doc/current/security/form_login_setup.html
EDIT
I've just tried something else. Log in with my browser, for generate a cookie, and tried to handcraft an other with same PHPSESSID
public function setUp(): void
{
parent::setUp(); // TODO: Change the autogenerated stub
$this->client = Client::createChromeClient();
$this->client->manage()->window()->maximize();
$cookie = new Cookie('PHPSESSID', 'pafvg5nommcooa60q14nqhool0');
$cookie->setDomain('127.0.0.1');
$cookie->setHttpOnly(true);
$cookie->setSecure(false);
$cookie->setPath('/');
$this->client->manage()->addCookie($cookie);
}
But get this error :
Facebook\WebDriver\Exception\InvalidCookieDomainException: invalid cookie domain
Domain is good, same as my web browser.
I will update as my investigations progressed.
EDIT 2
Ok... Got It.
According to this thread : Unable to set cookies in Selenium Webdriver
For setting-up cookie['domain'], you have to request firstly on the domain, THEN set-up the cookie...
SO, this is almost working :
public function setUp(): void
{
parent::setUp(); // TODO: Change the autogenerated stub
$this->client = Client::createChromeClient();
$this->client->manage()->window()->maximize();
$this->client->request('GET', 'http://127.0.0.1/randompage');
$handcookie = Cookie::createFromArray([
'name' => 'PHPSESSID',
'value' => 'pcvbf3sjlla16rfb1b1274qk01',
'domain' => '127.0.0.1',
'path' => '/'
]);
$this->client->manage()->addCookie($handcookie);
}
Next step : Find a way to generate a permanent cookie, without lifetime.
I think nobody will read this but i will update it in case someone else gets stuck.
I'm a begginer in Symfony 4 and I'm developing an API Rest. I want to create a PUT resource that can handle many update cases.
In my case, I have a user with many properties but I will take an example with 3 properties to keep things simple :
User {
username,
email,
password
}
My PUT resource can be called in order to update Username, update Email or update Password. For example, to update Username, the user of my API will send a PUT request with only username :
{
username: "New username"
}
Same for email and password, he will only send the property he wants to change.
My problem is in my Controller, I have to do things like this :
/**
* #Rest\Put("/user/{id}")
* #param Request $request
* #return View
*/
public function putUserRequest(Request $request)
{
$userId = $request->get('id');
$user = $this->doctrine->getRepository(User::class)->findOneBy('id' => $userId);
$userFromRequest = $this->serializer->deserialize($request->getContent(), User::class, 'json');
if ($userFromRequest->getUsername() != NULL) {
$user->setUsername($userFromRequest->getUsername())
}
if ($userFromRequest->getEmail() != NULL) {
$user->setEmail($userFromRequest->getEmail())
}
if ($userFromRequest->getPassword() != NULL) {
$user->setPassword($userFromRequest->getPassword())
}
// ...
}
In my example I have only 3 properties, but imagine when I have 30 properties.
With Symfony 3 I used forms to validate / save my datas :
$form->submit($request->request->all(), $clearMissing);
Where $clearMissing is false to keep datas not provided by the user of my API. I can't find a way to do it with serializer but I guess I'm doing things wrong.
Thanks.
If I understand correctly, You can use the validator Component like this :
/**
* #Rest\Put("/user/{id}")
* #param Request $request
* #return View
*/
public function putUserRequest(User $user, Request $request, ValidatorInterface $validator)
{
$data = $request->getContent();
$this->serializer->deserialize($data, User::class, 'json', ['object_to_populate' => $user]);
//At this moment, the data you sent is merged with your user entity
/** #var ConstraintViolationList $errors */
$errors = $validator->validate($user, null ,['groups' => 'user_update']);
if (count($errors) > 0) {
//return json reponse with formated errors;
}
//if ok $entityManager->flush() and Response Json with serialization group;
...
}
In your user class :
class User implements UserInterface
{
/**
* #Assert\Email(groups={"user_create", "user_update"})
*/
private $email;
/**
* #Assert\NotBlank(groups={"user_create", "user_update"})
* #Assert\Length(min=7, groups={"user_create", "user_update"})
*/
private $password;
/**
* #Assert\Length(min=2, groups={"user_create", "user_update"} )
*/
private $username;
}
Related Validator component documentation : https://symfony.com/doc/current/validation/groups.html
You can also check this project : https://github.com/attineos/relation-deserializer
I use Cartalyst Sentry for authentication. When I try to seed my database from command line, I get this error:
[Cartalyst\Sentry\Users\LoginRequiredException]
A login is required for a user, none given.
This is my DatabaseSeeder.php file:
<?php
class DatabaseSeeder extends Seeder {
/**
* Run the database seeds.
*
* #return void
*/
public function run()
{
Eloquent::unguard();
$this->call('PriceChangeOccuredTableSeeder');
}
}
And this is my PriceChangeOccuredTableSeeder.php file:
<?php
// Composer: "fzaninotto/faker": "v1.3.0"
use Faker\Factory as Faker;
class PriceChangeOccuredTableSeeder extends Seeder {
public function run() {
DB::table('price_change_occured')->delete();
User::create(array('product_id' => 1, 'owner_id' => 2, 'change_occured' => 1));
}
}
And this is my PriceChangeOccured model
<?php
class PriceChangeOccured extends \Eloquent {
public $table = 'price_change_occured';
}
if change your login from "EMAIL" to "USERNAME" ,and every thing was good,you should change these too:
in your seed add username too:
class UserSeeder extends Seeder
{
protected $admin_email = "admin#admin.com";
protected $admin_password = "password";
protected $admin_username = "naghipour.me";
}
find SentryUserRepository.php and find create function and change to this:
$data = array(
"email" => $input["email"],
"password" => $input["password"],
"username" => $input["username"]
);
Attention: you should add username filed in migration :
$table->string('username', 100)->unique();
and every where there is email you should add username too.
The error says that you are not adding a login to the user. And it seems that you aren't. Thus, you only need to add the login (or email) depending on how your User table works.
I'm assuming that a email/login and password woud be required for your user table. And you are not providing any of those when you create the user on this example.
I am a newbie to yii. I have stuck my mind with yii-tutorials for creating roles in yii. but I am not getting how can I create role in yii. means I want to create two roles admin & staff and I want to give different priviliage to them.
I have created a role in user table, but I am not getting that how can I create a role and can assign priviliages to them, please help me guys
Thanks in advance
In your copenents/UserIdentity.php
class UserIdentity extends CUserIdentity{
private $_id;
public function authenticate()
{
$record=Members::model()->findByAttributes(array('username'=>trim($this->username)));
if($record===null)
$this->errorCode=self::ERROR_USERNAME_INVALID;
else if($record->password!==md5(trim($this->password)))
$this->errorCode=self::ERROR_PASSWORD_INVALID;
else
{
$this->_id=$record->id;
$this->setState('username', $record->username);
$this->setState('name', $record->name);
$this->setState('type', $record->role);
$this->errorCode=self::ERROR_NONE;
}
return !$this->errorCode;
}
public function getId()
{
return $this->_id;
}
public function setId($id)
{
$this->_id = $id;
}
}
You can create a new column name as "role". set the members type "admin" or "staff" to role column.
Be careful to that line.
$this->setState('type', $record->role);
Create a new helper file. /protected/helpers/RoleHelper.php
class RoleHelper {
public static function GetRole(){
if (Yii::app()->user->type == "admin"){
//set the actions which admin can access
$actionlist = "'index','view','create','update','admin','delete'";
}
elseif (Yii::app()->user->type = "staff"){
//set the actions which staff can access
$actionlist = "'index','view','create','update'";
}
else {
$actionlist = "'index','view'";
}
return $actionlist;
}
}
and in your controllers -> accessRules function
public function accessRules()
{
return array(
array('allow', // allow authenticated user to perform 'create' and 'update' actions
'actions'=>array(RoleHelper::GetRole()),
'users'=>array('#'),
),
array('deny', // deny all users
'users'=>array('*'),
),
);
}
and dont forget to add 'application.helpers.*' to /config/main.php
'import'=>array(
'application.models.*',
'application.components.*',
'application.helpers.*',
),
This source is pretty good specially for beginners..I am using this method till now:
Simple RBAC in YII
Just follow the instructions given while having your desired modifications.
Concrete Example:
WebUser.php (/components/WebUser.php)
<?php
class WebUser extends CWebUser
{
/**
* Overrides a Yii method that is used for roles in controllers (accessRules).
*
* #param string $operation Name of the operation required (here, a role).
* #param mixed $params (opt) Parameters for this operation, usually the object to access.
* #return bool Permission granted?
*/
public function checkAccess($operation, $params=array())
{
if (empty($this->id)) {
// Not identified => no rights
return false;
}
$role = $this->getState("evalRoles");
if ($role === 'SuperAdmin') {
return 'SuperAdmin'; // admin role has access to everything
}
if ($role === 'Administrator') {
return 'Administrator'; // admin role has access to everything
}
if ($role === 'Professor') {
return 'Professor'; //Regular Teaching Professor, has limited access
}
// allow access if the operation request is the current user's role
return ($operation === $role);
}
}
Just connect it with your components/UserIdentity.php and config/main.php:
'components' => array(
// ...
'user' => array(
'class' => 'WebUser',
),
and thats it..
to check the role of the logged in:
Yii::app->checkAccess("roles");
where checkAccess is the name of your function in WebUser...
Please note that evalRoles is a column in your table that will supply the role of an account (on my link provided, that would be the word roles used in the major part snippet)
I am trying to save user's last logout time into a DB in Yii framework.
I have WebUser as:
<?php
// this file must be stored in:
// protected/components/WebUser.php
class WebUser extends CWebUser {
public function afterLogout()
{
$user=user::Model();
$user->logOutDateTime='TEST';
$user->saveAttributes(array('logOutDateTime'));
parent::afterLogout();
}
}
?>
and in config\main.php I have these lines
// application components
'components'=>array(
'user'=>array(
// enable cookie-based authentication
'class'=>'WebUser',
'allowAutoLogin'=>true,
)
For now I have set logOutDateTime datatype to varchar, to test, and I assume every time user logs out, it should write 'TEST' into database but it does nothing.
Where did I go wrong?
I don't think the afterLogout() still has the Yii::app()->user set, so I would do something like (untested):
public function beforeLogout()
{
if (parent::beforeLogout()) {
$user = User::model()->findByPk(Yii::app()->user->id); // assuming you have getId() mapped to id column
$user->logOutDateTime='TEST';
$user->saveAttributes(array('logOutDateTime'));
return true;
} else {
return false;
}
}
$user = user::Model();
should be:
$user = user::Model()->find(/* model_conditions */);