I am working on API in Yii2, where I need to use different authentication methods for different actions.
How can I set CompositeAuth for action1, action2 and action3, and HttpBasicAuth for action4 and action5?
public function behaviors()
{
return [
'basicAuth' => [
'class' => \yii\filters\auth\HttpBasicAuth::className(),
'auth' => function ($username, $password) {
$user = User::find()->where(['username' => $username])->one();
if ($user->verifyPassword($password)) {
return $user;
}
return null;
},
],
];
}
You can attach multiple auth behaviors and use only property to specify list of actions which should be affected by each behavior:
public function behaviors() {
return [
'compositeAuth' => [
'class' => \yii\filters\auth\CompositeAuth::className(),
'authMethods' => [/* ... */],
'only' => ['action1', 'action2', 'action3'],
],
'basicAuth' => [
'class' => \yii\filters\auth\HttpBasicAuth::className(),
'auth' => function ($username, $password) {
$user = User::find()->where(['username' => $username])->one();
if ($user->verifyPassword($password)) {
return $user;
}
return null;
},
'only' => ['action4', 'action5'],
],
];
}
Related
I've found a lot of answers on how to create Access Control that requires login to all controllers and actions.
The following post shows how I did all controllers require login:
Yii2 require all Controller and Action to login
I've used the code below under my components:
'as beforeRequest' => [
'class' => 'yii\filters\AccessControl',
'rules' => [
[
'allow' => true,
'actions' => ['login', 'error'],
],
[
'allow' => true,
'roles' => ['#'],
],
]
],
But, I want to add some exceptions to it. Some controllers need to have some actions visible to Guest.
I've tried to use this code inside my behaviors on ReportsController:
'access' => [
'class' => AccessControl::className(),
'rules' => [
[
'allow' => true,
'actions' => ['share'],
'roles' => ['?'],
],
],
]
Still get redirected to login.
I'm trying to to make actionShare($param) {} public to guests.
What am I missing?
Thanks for all your help!
First execute
yii migrate --migrationPath=#yii/rbac/migrations
from command prompt to create RBAC table in data base.
Then create RbacController in component folder
namespace app\components;
use yii;
use yii\web\Controller;
use yii\filters\AccessControl;
class RbacController extends Controller
{
public function RbacRule($modules = false)
{
$rules = false;
if ($modules){
$rules = [
'allow' => true,
'roles' => ['#'],
'matchCallback' => function ($rule, $action) {
$module = Yii::$app->controller->module->id;
$action = Yii::$app->controller->action->id;
$controller = Yii::$app->controller->id;
$route = "/$module/$controller/$action";
$post = Yii::$app->request->post();
if (\Yii::$app->user->can($route)) {
return true;
}
}
];
}else{
$rules = [
'allow' => true,
'roles' => ['#'],
'matchCallback' => function ($rule, $action) {
//$module = Yii::$app->controller->module->id;
$action = Yii::$app->controller->action->id;
$controller = Yii::$app->controller->id;
$route = "/$controller/$action";
$post = Yii::$app->request->post();
if (\Yii::$app->user->can($route)) {
return true;
}
}
];
}
return $rules;
// return true;
}
}
then extend to your controller using this RbacController instead of controller.
use app\components\RbacController;
class AdminController extends RbacController
{
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'rules' => [
// [
// 'actions' => ['login', 'logout'],
// 'allow' => true,
// 'roles' => ['?'],
// ],
parent::RbacRule(),
],
],
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'delete' => ['post'],
'bulk-delete' => ['post'],
],
],
];
}
.......
}
If your controller is inside Modules folder then you have to use
parent::RbacRule(TRUE) instead of parent::RbacRule(),
Trying to implement a GET method in Rest API, to query the user status e.g. GET user/:id/status
So getting the status of user id #1 would call /user/1/status
In config I have:
'urlManager' => [
'enablePrettyUrl' => true,
'enableStrictParsing' => true,
'showScriptName' => false,
'rules' => [
[
'class' => 'yii\rest\UrlRule',
'controller' => [
'v1/user'
],
'extraPatterns' => [
'GET status' => 'status',
],
'tokens' => [
'{id}' => '<id:\\w+>'
],
],
],
User Model:
namespace api\modules\v1\models;
use \yii\db\ActiveRecord;
class User extends ActiveRecord {
/**
* #inheritdoc
*/
public static function tableName() {
return 'user';
}
/**
* #inheritdoc
*/
public static function primaryKey() {
return [ 'id' ];
}
}
User Controller:
namespace api\modules\v1\controllers;
use yii\rest\ActiveController;
class UserController extends ActiveController {
public $modelClass = 'api\modules\v1\models\User';
public function actions() {
$actions = parent::actions();
unset(
$actions[ 'index' ],
$actions[ 'view' ],
$actions[ 'create' ],
$actions[ 'update' ],
$actions[ 'delete' ],
$actions[ 'options' ]
);
return $actions;
}
protected function verbs() {
return [
'status' => [ 'GET' ],
];
}
public function actionStatus( $id ) {
return 1;
}
}
But now I'm not sure on how to actually return the data for the call.
$user = User::findOne($id);
if ($user)
return Json::encode(['success'=>true, 'data'=>$user->status]);
else
return Json::encode(['success'=>false, 'message'=>"Can't find user"]);
I have this controller code for login:
public function actionLogin()
{
if (!\Yii::$app->user->isGuest) {
return $this->redirect(Yii::$app->request->baseUrl.'/telephone/index');
}
$model = new LoginForm();
if ($model->load(Yii::$app->request->post()) && $model->login()) {
return $this->redirect(Yii::$app->request->baseUrl.'/telephone/index');
}
return $this->render('login', [
'model' => $model,
]);
}
And for preventing the add and delete action for unauthorized users i used:
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'only' => ['add','delete'],
'rules' => [
// allow authenticated users
[
'allow' => true,
'roles' => ['#'],
],
// everything else is denied by default
],
],
];
}
But if unauthorized users clik add or delete, it is redirected to site/login. How can i change that controller and action?
There are different approaches to changing that route depending on the scope. They all involve changing the loginUrl property of the yii\web\User class.
Global
Edit config file.
'components' => [
'user' => [
'loginUrl' => ["controller/action"],
],
],
Controller/Action
Edit beforeAction method of the controller.
public function beforeAction($action)
{
// action-specific
if(in_array($action->id,['not', 'allowed', 'actions']))
Yii::$app->user->loginUrl = ["controller/action"];
// controller-wide
Yii::$app->user->loginUrl = ["controller/action"];
if (!parent::beforeAction($action)) {
return false;
}
return true;
}
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'only' => ['add','delete'],
'rules' => [
'allow' => true,
'actions' => ['add','delete'],
'roles' => ['#'],
'denyCallback' => function ($rule, $action) {
return $this->redirect('index.php?r=site/login');
}
],
],
];
}
When I try to post using Postman,I get this error {"name":"Bad Request","message":"Invalid JSON data in request body: Syntax error.","code":0,"status":400,"type":"yii\\web\\BadRequestHttpException"}
My controller is
`class CountryController extends ActiveController
{
public $modelClass = 'app\models\Country';
public function behaviors()
{
return [
[
'class' => 'yii\filters\ContentNegotiator',
'only' => ['index', 'view','create'],
'formats' => ['application/json' => Response::FORMAT_JSON,],
],
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'index'=>['get'],
'view'=>['get'],
'create'=>['post'],
'update'=>['put'],
'delete' => ['delete'],
'deleteall'=>['post'],
],
],
];
}
}`
added
'parsers' => [
'application/json' => 'yii\web\JsonParser',
]
in api/config.php file.
Where I am wrong??
Try this
public function behaviors()
{
return [
[
'class' => 'yii\filters\ContentNegotiator',
'only' => ['index', 'view','create'],
'formats' => ['application/json' => Response::FORMAT_JSON]
],
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'index'=>['get'],
'view'=>['get'],
'create'=>['post'],
'update'=>['post'],
'delete' => ['delete'],
'deleteall'=>['post'],
]
]
];
}
I am using wordpress 4.7 on php 7, also getting problems with the empty request body.
My Controller :
add_action('rest_api_init', function()
{
register_rest_route('v0', '/accounts/(?P<slug>[a-z0-9_\-]+)/accounts', array(
'methods' => 'GET',
'callback' => function($request)
{
try {
return 'hello';
}
catch (Exception $e) {
$error = json_decode($e->getMessage(), true);
return new WP_Error($error['status_code'], $error['message'], "");
}
}
));
});
Response Error :
{"code":"rest_invalid_json","message":"Invalid JSON body passed.","data":{"status":400,"json_error_code":4,"json_error_message":"Syntax error"}}
I did not found any solution rather than changing in WP core : wp-includes/rest-api/class-wp-rest-request.php and chaning line 672 for conditional check for empty body or not.
$params = json_decode( $this->get_body(), true );
Does anyone have a working example of this extension.
I'm talking about:
https://github.com/mdmsoft/yii2-admin
I'm looking for Yii app basic.
I installed and working properly, but I don't know how to configure "Roles" and "Rules"
At Yii 1.xxx I used http://www.yiiframework.com/extension/authbooster/ but this not working in Yii2.xx
Create a custom model AccessRules.php
<?php
namespace app\models;
class AccessRules extends \yii\filters\AccessRule
{
/**
* #inheritdoc
*/
protected function matchRole($user)
{
if (empty($this->roles)) {
return true;
}
foreach ($this->roles as $role) {
if ($role === '?') {
if ($user->getIsGuest()) {
return true;
}
} elseif ($role === '#') {
if (!$user->getIsGuest()) {
return true;
}
// Check if the user is logged in, and the roles match
} elseif (!$user->getIsGuest() && (int)$role === $user->identity->user_role) {
return true;
}
}
return false;
}
}
?>
Now in your Site Controller add the roles:
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
// We will override the default rule config with the new AccessRule class
'ruleConfig' => [
'class' => AccessRules::className(),
],
'only' => ['create', 'update', 'delete','index'],
'rules' => [
[
'actions' => ['create', 'update', 'delete','index'],
'allow' => true,
// Allow admin to create
'roles' => [
'1'
],
]
],
],
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'logout' => ['post'],
],
],
];
}