Hi developers I am new to YII , I have installed the YII2 framework and want a RBAC I have installed mdmsoft/yii2-admin module , but I do not know how to create RULE class, where to create it and then how to use. When I create a role in admin section it say , enter a Class Name. I don't know how to create and use the RULE feature of YII. I have attached the screen shot.
If you are using an Advanced template here are the steps;
Create a directory under frontend and rename it rbac
Create a file under this new directory, say, AuthorRule.php. Here is a sample file given in the official docs;
namespace app\rbac;
use yii\rbac\Rule;
use app\models\Post;
/**
* Checks if authorID matches user passed via params
*/
class AuthorRule extends Rule
{
public $name = 'isAuthor';
/**
* #param string|int $user the user ID.
* #param Item $item the role or permission that this rule is associated with
* #param array $params parameters passed to ManagerInterface::checkAccess().
* #return bool a value indicating whether the rule permits the role or permission it is associated with.
*/
public function execute($user, $item, $params)
{
return isset($params['post']) ? $params['post']->createdBy == $user : false;
}
}
Next step is to navigate to http://localhost/path/to/index.php?r=admin/rule and create a new rule with class name \app\rbac\AuthorRule
Finally you can add the new rule to roles and permissions depending on your needs.
You can read the official docs for more information on rules; the official docs.
Related
I am using the #Security annotation to control which roles have access to certain routes in my Symfony 3.4 application, it works when I am logged in however when the user object doesn't exist such as when the session times out I get the following exception thrown.
Unable to get a property on a non-object.
vendor/symfony/symfony/src/Symfony/Component/ExpressionLanguage/ExpressionLanguage.php:78
at
Symfony\Component\ExpressionLanguage\ExpressionLanguage->evaluate('\'ROLE_MANAGER\'
in user.getRoles()',
My method definition looks like this:
/**
* #Route("/club/{id}/trophies", name="club_trophies", methods={"GET","POST"})
* #IsGranted("IS_AUTHENTICATED_FULLY")
* #Security("'ROLE_MANAGER' in user.getRoles()")
* #param Club $club
* #return Response
*/
public function trophies(Club $club): Response
{
Is there a way using the Symfony Expression Language, or similar, that I can check that user exists. Or is there a better way?
When you are not authenticated, the value of user is null, so it's normal that your check is throwing an exception (as you're trying to access the method getRoles() of a null object).
The proper ways to check if a user has a given role using annotations are :
#IsGranted("ROLE_MANAGER")
Or :
#Security("is_granted('ROLE_MANAGER')")
You can see more here : https://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/security.html
I have installed yii2mod/yii2-rbac from this url - https://github.com/yii2mod/yii2-rbac in yii2-basic.
everything is working fine except using/allowing owner data.
from this link:https://www.yiiframework.com/doc/guide/2.0/en/security-authorization
I have created a folder in root rbac and file AuthorRule.php and code:
namespace app\rbac;
use yii\rbac\Rule;
//use app\models\Post;
/**
* Checks if authorID matches user passed via params
*/
class AuthorRule extends Rule
{
/**
* #var string
*/
public $name = 'isAuthor';
/**
* #param string|int $user the user ID.
* #param Item $item the role or permission that this rule is associated with
* #param array $params parameters passed to ManagerInterface::checkAccess().
* #return bool a value indicating whether the rule permits the role or permission it is associated with.
*/
public function execute($user, $item, $params)
{
return isset($params['post']) ? $params['post']->createdBy == $user : false;
}
}
but when I try to add the rule in permission(either AuthorRule or isAuthor under permission I created updateOwnRecord, I am getting the error, the rule doesn't exist.
What I am missing here?
but when I try to add the rule in permission(either AuthorRule or
isAuthor under permission I created updateOwnRecord, I am getting the
error, the rule doesn't exist
Not sure where you are getting the error you mentioned as there is no relevant code, but looking at your details i recon you havent understood the process correctly.
Create a permission updatePost in the auth_item .
Add AuthorRule class's serialized instance to auth_rule table.
Create a new permission updateOwnPostand specify the rule name i.e isAuthor.
Add the permission updatePost as a child to UpdateOwnPost in the auth_item_child table.
the isAuthor will be the name of the rule that you will supply to the updateOwnPost permission's rule_name column.
Add the updatePost as a child of the role you want to use the rule for, like user or anyother you have created for the standard user role.
See the below code you can run it once via any temporary action for now, we will discuss it's place later in the answer below.
$auth = Yii::$app->authManager;
$updatePost = $auth->getPermission('updatePost');
//change it to whichever role you want to assign it like `user` `admin` or any other role
$role = $auth->getRole('user');
// add the rule
$rule = new \app\rbac\AuthorRule;
$auth->add($rule);
// add the "updateOwnPost" permission and associate the rule with it.
$updateOwnPost = $auth->createPermission('updateOwnPost');
$updateOwnPost->description = 'Update own post';
$updateOwnPost->ruleName = $rule->name;
$auth->add($updateOwnPost);
// "updateOwnPost" will be used from "updatePost"
$auth->addChild($updateOwnPost, $updatePost);
// allow "author" to update their own posts
$auth->addChild($role, $updateOwnPost);
Now if all goes well and you can add a rule by running the code above
Remember You need to check the updatePost rule in the check Yii::$app->user->can() and not updateOwnPost and pass the Post model instance along as the second parameter
Like this
if (\Yii::$app->user->can('updatePost', ['post' => $post])) {
// update post
}
About The code Placement in the current application
If you want to have a separate interface where you can add create all with a form then you can follow dektrium-rbac code available already where it provides complete crud that you can use according to your own requirements.
For the reference see below
Add Rule Form
RuleController::actionCreate
RuleModel::create()
Note: if you have a lot of controllers and you want to associate this rule with every update action inside the controllers (Given that all the associated models have the created_by field) then you might go for the console\Controller and run such processes via console, so that every new controller/update can be associated with the rule repeating the above process inside a loop. For the console controller usage in basic-app see here
I'm currently researching Symfony CMF and PHPCR for a project I recently started. What I'm currently trying to figure out is how to create a Route and save it into the database. As far as I understand, I must use Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Phpcr\Route and persist the element into the database. This works fine, but automatically generates a route path, which is not what I want. What I need to do is generate a custom route which links to a specific controller. Here is my code:
$em = $this->get('doctrine_phpcr.odm.document_manager');
$parent = $em->find(null, '/cms/routes');
$route = new \Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Phpcr\Route();
$route->setParentDocument($parent);
$route->setName('my_route_name');
$route->setDefault('_controller', 'AppBaseBundle:Frontend/Users:index');
$em->persist($route);
$em->flush();
If i execute this code, the generated route will be /cms/routes/my_route_name. From what I can see, you could use $route->setPath('/testing');, but that generates the following exception:
Can not determine the prefix. Either this is a new, unpersisted document or the listener that calls setPrefix is not set up correctly.
Does anybody have any ideas how to solve this?
In PHPCR, every document has a path where it is store. If you are familiar with doctrine ORM, the path has the role of the ID. The difference with ORM is that all documents (regardless of their type) live in the same tree. This is great, because your route can reference just anything, it is not limited to specific document types. But we need to create some structure with the paths. This is why we have the prefix concept. All routes are placed under a prefix (/cms/routes by default). That part of the document path is removed for the URL path. So repository path /cms/route/testing is the url domain.com/testing.
About your sample code: Usually, you want to configure the controller either by class of the content document or by route "type" attribute to avoid storing a controller name into your database to allow for future refactoring. A lot of this is explained in the [routing chapter of the CMF documentation][1] but the prefix is only used there, not explicitly explained. We need to improve the documentation there.
[1] http://symfony.com/doc/master/cmf/book/routing.html
I managed to find a way to overcome this issue. Because in my project I also have the RouteAutoBundle, I created a class which extends \Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Phpcr\Route. Inside that class I added:
/**
* #PHPCR\Document(referenceable=true)
*/
class MenuRoute extends Route
{
protected $url;
/**
* Get $this->url
*
* #return mixed
*/
public function getUrl() {
return $this->url;
}
/**
* Set $this->url
*
* #param mixed $url
*/
public function setUrl($url) {
$this->url = $url;
}
}
After that I added this to cmf_routing_auto.yml:
App\MenuBundle\Document\MenuRoute:
uri_schema: /{getUrl}
token_providers:
getUrl: [content_method, { method: getUrl }]
So now one would just create an instance of MenuRoute (just like when using Route) and call the method setUrl($your_url) passing the desired url.
If anybody finds a better way, I'm opened to suggestions.
I want two endpoints for my custom api which are
Create custom rules in a magento cart (URL= magento.com/coupondemo/generate)
Create coupon codes for a particular rule (URL= magento.com//coupondemo/rules/:rule_id/codes)
I've followed this tutorial to and coupon codes in Magento and I have code that can create a rule in Magento too. However, I've no clue how to create the two endpoints in my custom rest api as I am only able to create one.
I have the following routes in api2.xml
<routes>
<route_collection>
<route>/coupondemo/generate</route>
<action_type>entity</action_type>
</route_collection>
<route_collection>
<route>/coupondemo/rules/:rule_id/codes</route>
<action_type>collection</action_type>
</route_collection>
</routes>
my v1.php's skeleton is as follows
<?php
/* Coupon AutoGen REST API
*
* #category CouponDemo
* #package CouponDemo_AutoGen
* #author Chuck Hudson (used with permission). For more recipes, see Chuck's book http://shop.oreilly.com/product/0636920023968.do
*/
class CouponDemo_AutoGen_Model_Api2_Coupon_Rest_Admin_V1 extends CouponDemo_AutoGen_Model_Api2_Coupon
{
/**
* Generate one or more coupon codes using the Generate Coupons rule defined in Magento.
* Expected parameters are:
* {
* 'qty': int, - number of coupon codes to instruct Magento to generate
* 'length': int, - length of each generated coupon code
* 'format': string, - alphanum (for alphanumeric codes), alpha (for alphabetical codes), and num (for numeric codes)
* }
*
* #param array $couponData
* #return string|void
*/
protected function _create($couponData)
{
}
protected function _retrieveCollection()
{
}
protected function _retrieve($couponDatas)
{
}
}
The problem is that both the routes call the _create methods in my v1.php. I want to have the first route call a custom method with an array as a parameter. So how can I do that?
I tried using this route
<!-- Call For V1.php _retrieve() -->
<route_entity_count>
<route>/coupondemo/generate</route>
<action_type>entity</action_type>
</route_entity_count>
which calls the _retrieve method but it doesn't allow the parameter to be passed in.
How should I handle the first route then?
When retrieving models from database and sending them to the client I want to include for each model the url to that resource.
Let's take as example this Article model, with:
id
title
content
etc.
Storing the url to an article in the DB doesn't make sense, because it can be easily made up from id and title:
ex: http://www.example.com/articles/article_id/article_title
So, this is what I am doing now:
I use the $appends array:
/**
* Additional attributes
*
* #var array
*/
protected $appends = array('article_url');
and created a getter for article_url:
/**
* Get the article url attribute
*
* #return string
*/
protected function getArticleUrlAttribute()
{
return $this->exists
? url('articles', $parameters = array(
$this->getKey(),
Str::title(Str::limit($this->title, 100))
))
: null;
}
This works just fine. The problem is, that probably the model should not include any logic for creating urls. What is a good approach for this problem? Where should I create the
url to the article before sending it to the client?
That sort of logic would usually go in whatever your framework's routing engine is. For instance, since it sounds like you're using Laravel, you'd probably make a Named Route -- call it, say, "canonical_article".
Then you can use the link_to_route helper to have your framework generate the URL.