How to prevent all detailView show data from another user ??
For example, this happens when you type an product ID of another user in the URL. The detailView shows the details of the product normally, however belongs to another User, and may even change it and delete it.
You can do something like this in the controller if you don't want to use RBAC :
protected function findModel($id)
{
//Check if the author is the current user
if (($model = Product::findOne($id)) !== null && $model->author_id==Yii::$app->user->id) {
return $model;
} else {
throw new NotFoundHttpException('The requested page does not exist.');
}
}
Like this users which are not the author can't view, update or delete the product.
http://www.yiiframework.com/forum/index.php/topic/61915-prevent-show-data-from-another-user/page__view__findpost__p__274644
Several options:
1) simplest one, in the controller before showing the view check that the current user can see the product. If he cannot redirect him (by throwing an error) to a 404 page (or whatever error you want to show).
2) use RBAC to set up roles and what those roles can do. This is the most professional option
3) you may be able to modify the accessfilter to do this too too
If you need to ask how to do this go with option 1.
If you want option 2 or 3 start by reading this http://www.yiiframework.com/doc-2.0/guide-security-authorization.html
An example to what Mihai have suggested.
public function behaviors()
{
return [
'accessControl' => [
'class' => \yii\filters\AccessControl::className(),
'rules' => [
[
'actions' => ['view'],
'allow' => true,
'matchCallback' => function () {
$request = \Yii::$app->request;
$user = \Yii::$app->user->identity;
$product = Product::findOne($request->get('id'));
if ($user && $product->owner_id == $user->id) {
return true;
}
return false;
}
],
[
'allow' => false,
'roles' => ['*'],
],
],
]
];
}
Related
I have User table which has a field called 'society_id' Which defines which society the user belongs to. Similarly, I have 'society_id' field in another table called 'expense_details' which identifies the society_id of the user who has entered the data in 'expense_details'.
this is my user table
https://i.stack.imgur.com/1hBky.png
this is my expense-details table
https://i.stack.imgur.com/Z3cQU.png
I know we can access the society_id of logged in user like this :
I want Logged in users to access their view but I want the user not to access data from table 'expense_details' related to other users with change url.
I know we can get society_id of logged in user like this Yii::$app->user->identity->society_id
But I am wondering how can i use it here and what changes i am supposed to make in my actionView and/or Model.
Here is my Expensedetails view controller.
public function actionView($id) {
$details = \app\models\ExpenseDetails::find()->where(['expense_id' => $id])->all();
$searchModel = new \app\models\ExpenseDetailsSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
$dataProvider->query->where("expense_id=$id");
return $this->render('view', [
'model' => $this->findModel($id),
'details' => $details,
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
]);
}
PS : English is not my native language. I am newbie to yii2 and stackoverflow, please excuse me for the mistakes. Thanks.
I solved it.
In My ExpenseDetails Model
protected function findModel($id)
{
if (($model =ExpenseDetails::findOne($id)) !== null) {
return $model;
}
throw new NotFoundHttpException('The requested page does not exist.');
}
In My Expensedetails view controller
protected function findModel($id)
{
if (($model = ExpenseDetails::findOne($id)) !== null) {
return $model;
}
throw new NotFoundHttpException('The requested page does not exist.');
}
As each user has society_id which can be same for any 2 user's records, so when you will fetch the table like this:
ExpenseDetails::find()->where(['expense_id' => $id, 'society_id' => Yii::$app->user->identity->society_id])->all();
it will return all the records on specific expense_id and specific society_id but those records would be of multiple users, if you want another condition that one user can not access anothers user's record, you can add "user_id" attribute in "expense_details" table and set the "users" table "id" attribute to it, as per need so you can fetch the records with specific expense_id, society_id and specific "user_id":
ExpenseDetails::find()->where(['expense_id' => $id, 'society_id' => Yii::$app->user->identity->society_id, "user_id" => 1])->all();
or for current logged in user :
ExpenseDetails::find()->where(['expense_id' => $id, 'society_id' => Yii::$app->user->identity->society_id, "user_id" => Yii::$app->user->id])->all();
Im using yii2 for my project. I need to use two different tables for login (Login page is same). I have two models Admin and User. And i have one LoginFrom for login.
I can login properly but the problem is after logged in i cannot get whether the admin is logged in or the user is logged in.
I have set it in config file (web.php) like below:
'admin' => [
'identityClass' => 'app\models\Admin',
'enableAutoLogin' => false,
'class' => 'yii\web\User',
'authTimeout' => 1200, // in Seconds. 1200 seconds means 20 mins
],
'user' => [
'identityClass' => 'app\models\User',
'enableAutoLogin' => false,
'authTimeout' => 1200
],
So im getting logged in user details by using below method:
\Yii::$app->admin->identity;
\Yii::$app->user->identity;
My problem is if im logged in as admin i can get user values also by using this : \Yii::$app->user->identity; or if im logged in as user i can get admin values by using this : \Yii::$app->admin->identity;.
My LoginForm.php is :
<?php
namespace app\models;
use Yii;
use yii\base\Model;
class LoginForm extends Model
{
public $username;
public $password;
public $rememberMe = true;
private $_user = false;
public function rules()
{
return [
// username and password are both required
[['username', 'password'], 'required'],
// rememberMe must be a boolean value
['rememberMe', 'boolean'],
// password is validated by validatePassword()
['password', 'validatePassword'],
];
}
public function validatePassword($attribute, $params)
{
if (!$this->hasErrors()) {
$user = $this->getUser();
if (!$user || !$user->validatePassword($this->password)) {
$this->addError($attribute, 'Incorrect username or password.');
}
}
}
public function login()
{
if ($this->validate()) {
if(!empty($this->getUser()['phone_number'])) {
return Yii::$app->admin->login($this->getUser(), $this->rememberMe ? 3600*24*30 : 0);
} else {
return Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600*24*30 : 0);
}
}
return false;
}
public function getUser()
{
if ($this->_user === false) {
$this->_user = User::findByUsername($this->username);
if(!$this->_user) {
$this->_user = Admin::findByUsername($this->username);
}
}
return $this->_user;
}
}
I cant find the problem and if i logged in identity creating for both the users so i could'nt write access rules in particular controller to allow admin only to access the controller.Please help me :(
From reading the comments I think you should just create a unifying table for the two identities where they both get their IDs from. Then make that the identity class. The reason you are able to see the details in both identity classes is that they have the same ID.
in my behaviours I have specified that actionList can only be viewed by authenticated users.
$behaviors [ 'access' ] = [
'class' => AccessControl::className(),
'rules' => [
[
'actions' => [ 'list' ],
'allow' => ['#'],
]
],
];
In actionList I'm getting the user_id:
public function actionList() {
$user_id = \Yii::$app->user->identity->id;
return $this->render( 'list' );
}
All good, but if you go to this action when not logged in, you get an error:
PHP Notice – yii\base\ErrorException
Trying to get property of non-object
Makes sense, I'm not logged in so I don't have a user id, but why does the code go that far? If I comment the $user_id = \Yii::$app->user->identity->id; out, I get redirected to the login page, which is the expected behaviour. I don't think I should have to do yet another check to see if someone is logged in in the action itself, shouldn't that be handled by the behaviours['access'] beforehand?
Try this changing the allow and roles attributes:
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'rules' => [
[
'actions' => ['list'],
'allow' => true,
'roles' => ['#'],
],
], // rules
], // access
];
}
More info here.
Here is my cent to the already good answers above
Add following code to the main controller file in your project (not the base controller) but some controller above this which is base for every other controller
/**
* Check if user is logged in and not logged out
*
* #param type $action
* #return type
*/
public function beforeAction($action) {
$this->enableCsrfValidation = false;
if(!empty($action) && $action->actionMethod == 'actionLogin') {
return true;
}
/* Check User's Login Status */
if (is_null(Yii::$app->user->identity)) {
$this->redirect(Url::to(['../site/login']));
Yii::$app->end();
}
return true;
}
I have read the description over,
Once a user is authenticated through the provider the authenticator gets the user profile from the identity provider and using that tries to find the corresponding user record in your app's users table. If no user is found and registrationCallback option is specified the specified method from the User model is called. You can use the callback to save user record to database.
But where to define/declare registrationCallback
If you want user to register if not exist then this code will execute :
if (!empty($this->_config['registrationCallback'])) {
$return = call_user_func_array(
[
TableRegistry::get($userModel),
$this->_config['registrationCallback']
],
[$provider, $providerProfile]
);
if ($return) {
$user = $this->_fetchUserFromDb($conditions);
if ($user) {
return $user;
}
}
You need to define the registration function in config ( in __construct) and regarding call_user_func_array read this link - https://php.net/call-user-func-array
To Store user in database after login
1>defines the function in UsersTabel.php
public function registration($provider, $profile) {
$user = $this->newEntity([
'username' => $profile->displayName,
'provider' => $provider,
'provider_uid' => $profile->identifier
]);
if(!$this->save($user))
{
Log::write(LOG_ERR, 'Failed to create new user record');
return false;
}
return true;
}
2>Replace the function of file vendor ▸ admad ▸ cakephp-hybridauth ▸ src ▸ Auth▸ HybridAuthAuthenticate.php
public function __construct(ComponentRegistry $registry, $config)
{
$this->config([
'fields' => [
'provider' => 'provider',
'provider_uid' => 'provider_uid',
'openid_identifier' => 'openid_identifier'
],
'hauth_return_to' => null,
'registrationCallback'=>'registration'
]);
parent::__construct($registry, $config);
}
I have the main controller from which the others are inherited. Code is something like this
public function init()
{
$this->on('beforeAction', function ($event) {
...
if (Yii::$app->getUser()->isGuest) {
$request = Yii::$app->getRequest();
// dont remember login page or ajax-request
if (!($request->getIsAjax() || strpos($request->getUrl(), 'login') !== false)) {
Yii::$app->getUser()->setReturnUrl($request->getUrl());
}
}
}
...
});
}
It works perfectly for all pages, except the page with captcha. All the pages with captcha are redirected to something like this - /captcha/?v=xxxxxxxxxxxxxx
If the object is logged Yii::$app->getRequest() then I see that for pages with captcha it is used twice. For the first time the object is corect, and the second time I see the object with captcha.
How can I solve this problem with yii? Is there a chance not to track the request for captcha?
The default (generated) controller uses something like this:
public function actions()
{
return [
'captcha' => [
'class' => 'yii\captcha\CaptchaAction',
],
];
}
Does your controller contain something like this?
This means that there is an action "captcha" that is used for displaying captchas (it returns the image). When you have a page displaying a captcha the image is called after the page you want to return to. Therefore that latest page visited is the one with the captcha.
I think you have to filter out this action.
Another possibility could be to use the default $controller->goBack() method. I think this handles registering of the returnUrl by default.
Reference: Class yii\web\Controller
Guid security authorization
Use Access Control Filter(ACF) in your controller.
use yii\web\Controller;
use yii\filters\AccessControl;
class SiteController extends Controller
{
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'only' => ['login', 'logout', 'signup'],
'rules' => [
[
'allow' => true,
'actions' => ['login', 'signup'],
'roles' => ['?'],
],
[
'allow' => true,
'actions' => ['logout'],
'roles' => ['#'],
],
],
],
];
}
// ...
}