Yii2: Can I apply authenticator behavior just to some actions? - php

I always got "You are requesting with an invalid credential." but I need to have a public endpoint specifically "view" action that everybody can access whitout send access token and keep the other actions with token validation
This is part of my Api controller:
/**
* #inheritdoc
*/
public function behaviors()
{
return [
'contentNegotiator' => [
'class' => ContentNegotiator::className(),
'formats' => [
'application/json' => Response::FORMAT_JSON,
//'application/xml' => Response::FORMAT_XML,
],
],
'verbFilter' => [
'class' => VerbFilter::className(),
'actions' => $this->verbs(),
],
'access' => [
'class' => AccessControl::className(),
'only' => ['view'],
'rules' => [
[
'actions' => ['view'],
'allow' => true,
'roles' => ['?'],
],
],
],
'authenticator' => [
'class' => CompositeAuth::className(),
'authMethods' => [
HttpBasicAuth::className(),
HttpBearerAuth::className(),
QueryParamAuth::className(),
],
],
'rateLimiter' => [
'class' => RateLimiter::className(),
],
];
}
I try using:
'access' => [
'class' => AccessControl::className(),
'only' => ['view'],
'rules' => [
[
'actions' => ['view'],
'allow' => true,
'roles' => ['?'],
],
],
],
But the authenticator behavior does not allow that my view action are a public action

I found the solutions is just using 'only' or 'except' key on the authenticator behavior
'authenticator' => [
'class' => CompositeAuth::className(),
'except' => ['view'],
'authMethods' => [
HttpBasicAuth::className(),
HttpBearerAuth::className(),
QueryParamAuth::className(),
],
],
Source:
https://github.com/yiisoft/yii2/issues/4575
https://github.com/yiisoft/yii2/blob/master/docs/guide/structure-filters.md#using-filters-
Thanks, Enjoy Yii2 and REST ;)

There is two property to bypass authenticator on actions
1. only => bypass the rest of action in array configured
2. except => bypass only configured in array
public function behaviors()
{
$behaviors = parent::behaviors();
$behaviors['authenticator'] = [
'class' => CompositeAuth::className(),
'except' => ['login', 'register','regenerate'],
//'only'=>['index'],
'authMethods' => [
[
'class' => HttpBasicAuth::className(),
'auth' => function ($username, $password) {
$user = User::findByLogin($username);
return $user->validatePassword($password)
? $user
: null;
}
],
HttpBearerAuth::className(),
QueryParamAuth::className()
],
];
return $behaviors;
}

Related

Getting unknown property: Da\User\Module::isGuest yii2-usuario

I'm install 2amigos/yii2-usuario:~1.5.1 on a yii2-basic-template, using https://yii2-usuario.readthedocs.io/en/latest/. However, it returns this error (Getting unknown property: Da\User\Module::isGuest yii2-usuario) in any view.
My config/console.php:
'components' => [
...
'authManager' => [
'class'=> 'yii\rbac\DbManager',
],
...
],
'controllerMap' => [
'migrate' => [
'class' => \yii\console\controllers\MigrateController::class,
'migrationPath' => [
'#app/migrations',
'#yii/rbac/migrations', // Just in case you forgot to run it on console (see next note)
],
'migrationNamespaces' => [
'Da\User\Migration',
],
],
],
My config/web.php:
'components' => [
...
'user' => [
'class' => Da\User\Module::class,
'classMap' => [
'User' => app\models\User::class,
],
],
'authManager' => [
'class' => 'yii\rbac\DbManager',
],
'view' => [
'theme' => [
'pathMap' => [
'#Da/User/resources/views' => '#app/views/user'
]
]
]
],
I managed to solve it with help.
Follow the line:
Remove : config/web.php
'user' => [
'identityClass' => 'app\models\Users',
'enableAutoLogin' => true,
'enableSession' => true,
],
'user-management' => [
'class' => 'webvimark\modules\UserManagement\UserManagementModule',
'on beforeAction'=>function(yii\base\ActionEvent $event) {
if ( $event->action->uniqueId == 'user-management/auth/login' ){
$event->action->controller->layout = 'loginLayout.php';
};
},
],
add into config/web.php:
'components' =>[ ...
'authManager' => [
'class' => 'yii\rbac\DbManager',
],
'view' => ['theme' => [ 'pathMap' => ['#Da/User/resources/views' => '#app/views/user']]] //If your view is modified.
]
'modules' => ['user' => [
'class' => \Da\User\Module::class,
'allowAccountDelete' => true,
'enableRegistration' => false,
'administratorPermissionName' => 'user-management']
...]
``

Zend action controller can't be called

I want to build a Zend-3-MVC application which can handle SOAP requests. It should therefore act as an SOAP server.
First of all I created the following controller:
<?php
namespace MyProject\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\Soap\AutoDiscover as WsdlAutoDiscover;
use Zend\Soap\Server as SoapServer;
class SoapController extends AbstractActionController
{
public function wsdlAction()
{
$request = $this->getRequest();
$wsdl = new WsdlAutoDiscover();
$this->populateServer($wsdl);
$response = $this->getResponse();
$response->getHeaders()->addHeaderLine('Content-Type', 'application/wsdl+xml');
$response->setContent($wsdl->toXml());
return $response;
}
public function serverAction()
{
$request = $this->getRequest();
$server = new SoapServer(
$this->url()
->fromRoute('soap/wsdl', [], ['force_canonical' => true]),
[
'actor' => $this->url()
->fromRoute('soap/server', [], ['force_canonical' => true]),
]
);
$server->setReturnResponse(true);
$this->populateServer($server);
$soapResponse = $server->handle($request->getContent());
$response = $this->getResponse();
$response->getHeaders()->addHeaderLine('Content-Type', 'application/soap+xml');
$response->setContent($soapResponse);
return $response;
}
}
And this is my router.global.php in config/autoload:
<?php
use Zend\Router\Http\Literal;
return [
'router' => [
'routes' => [
'soap' => [
'type' => Literal::class,
'options' => [
'route' => '/soap',
],
'may_terminate' => false,
'child_routes' => [
'wsdl' => [
'type' => Literal::class,
'options' => [
'route' => '/wsdl',
'defaults' => [
'controller' => \MyProject\Controller\SoapController::class,
'action' => 'wsdl',
],
],
'may_terminate' => true,
],
],
],
],
],
];
And now I make an SOAP GET request to
https://example.com/soap/wsdl
But the route can't be resolved. I expect that the wsdlAction method is called but I only get a 404.
You need to register your controller also.
use Zend\ServiceManager\Factory\InvokableFactory;
'controllers' => [
'factories' => [
MyProject\Controller\SoapController::class => InvokableFactory::class
],
],
So, now your code should be :
use Zend\Router\Http\Literal;
use Zend\ServiceManager\Factory\InvokableFactory;
return [
'controllers' => [
'factories' => [
MyProject\Controller\SoapController::class => InvokableFactory::class
],
],
'router' => [
'routes' => [
'soap' => [
'type' => Literal::class,
'options' => [
'route' => '/soap',
],
'may_terminate' => false,
'child_routes' => [
'wsdl' => [
'type' => Literal::class,
'options' => [
'route' => '/wsdl',
'defaults' => [
'controller' => MyProject\Controller\SoapController::class,
'action' => 'wsdl',
],
],
'may_terminate' => true,
],
],
],
],
],
];

Zend Framework 3 Redirect

Background: I am using REST methods only.
I've called a create() method, which returns the id of the record I have created, and I want to call a different controller's get() method with that id.
module.config.php :
namespace PrivateStatement;
use Zend\Router\Http\Literal;
use Zend\Router\Http\Method;
return [
'router' => [
'routes' => [
'privateStatement' => [
'type' => Literal::class,
'options' => [
'route' => '/private-statements/private-statements',
'defaults' => [
'controller' => Controller\PrivateStatementController::class,
],
],
'child_routes' => [
'get' => [
'type' => Method::class,
'options' => [
'verb' => 'get',
'defaults' => [
'modules' => [
],
],
],
'may_terminate' => true,
],
'post' => [
'type' => Method::class,
'options' => [
'verb' => 'post',
'defaults' => [
'modules' => [
],
'params' => [
],
'requestVo' => '',
'controller' => Controller\PrivateStatementCreateController::class,
],
],
'may_terminate' => true,
],
],
],
],
],
'view_manager' => [
'strategies' => [
'ViewJsonStrategy',
],
],
];
In the PrivateStatementCreateController, I have the create() function:
public function create($data)
{
$requiredParams = [
PrivateStatementConstants::COLUMN_PROPERTY_ID,
PrivateStatementConstants::COLUMN_STOCK_UNIT_ID,
PrivateStatementConstants::API_FROM,
PrivateStatementConstants::API_TO,
];
$validRequest = ControllerUtil::verifyRequiredParams($requiredParams, $data);
if ($validRequest) {
$personId = $this->authResult->getIdentity();
$id = $this->model->createPrivateStatementService(
$data[PrivateStatementConstants::COLUMN_PROPERTY_ID],
$data[PrivateStatementConstants::COLUMN_STOCK_UNIT_ID],
$data[PrivateStatementConstants::API_FROM],
$data[PrivateStatementConstants::API_TO],
$personId
);
if ($id) {
return $this->redirect()->toRoute('privateStatement', array('action' => 'get', 'params' => array('private_statement_id' => $id)));
} else {
$this->getResponse()->setStatusCode(Response::STATUS_CODE_400);
}
} else {
$this->getResponse()->setStatusCode(Response::STATUS_CODE_400);
}
return new JsonModel([]);
}
The part I'm currently struggling with is return $this->redirect()->toRoute('privateStatement', array('action' => 'get', 'params' => array('private_statement_id' => $id)));
When I call this an exception gets thrown with the message Part route may not terminate - I honestly don't know how to continue from here - I only need to call the get() function in the PrivateStatementController and return the results.

urlManager for module Yii2

I've got a basic Yii2 project, in which i created a separate module "rest". I have set up urlManager in config/web.php file. It works fine for common url, but it seems to me it is not working with url starting with my module name: rest/.. I have actionAuth() in AuthController in my rest module, and it is accessible with this url: test.ru/auth/auth. But i want it to be accessible with this url:test.ru/auth. I tried to write like this in web.php :
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'rules' => [
[
'class' => 'yii\rest\UrlRule',
'controller' => 'rest\auth',
'extraPatterns' => [
'POST /' => 'auth',
],
'pluralize' => false,
],
],
],
But it does not work(not found error in browser).
I also tried like this:
'rules' => [
[
'class' => 'yii\rest\UrlRule',
'controller' => 'rest\auth',
'extraPatterns' => [
'POST rest/auth' => 'auth',
],
'pluralize' => false,
],
],
],
It seems to me that urlManager does not want to work for module. Next i tried to write the same code in my Module.php in rest/ directory. But it produced many errors. I think because of the same error things like that dont work too:`
'class' => 'yii\rest\UrlRule',
'controller' => 'rest\city',
'extraPatterns' => [
'DELETE {id}' => 'delete',
],
`
So my question is: how to set up urlManager for module in Yii2? I need to configure HTTP DELETE method, post methods work without any settings in urlManager.
The whole web.php file:
<?php
$params = require(__DIR__ . '/params.php');
$config = [
'id' => 'basic',
'basePath' => dirname(__DIR__),
'bootstrap' => ['log'],
'language' => 'ru',
'components' => [
'authManager' => [
'class' => 'yii\rbac\DbManager',
],
'request' => [
// !!! insert a secret key in the following (if it is empty) - this is required by cookie validation
'cookieValidationKey' => 'xxxxxxx',
'parsers' => [
'application/json' => 'yii\web\JsonParser',
]
],
'cache' => [
'class' => 'yii\caching\FileCache',
],
'user' => [
'identityClass' => 'app\models\User',
// 'loginUrl' => ['site/login'],
],
'errorHandler' => [
'errorAction' => 'site/error',
],
'mailer' => [
'class' => 'yii\swiftmailer\Mailer',
// send all mails to a file by default. You have to set
// 'useFileTransport' to false and configure a transport
// for the mailer to send real emails.
'useFileTransport' => true,
],
'log' => [
'traceLevel' => YII_DEBUG ? 3 : 0,
'targets' => [
[
'class' => 'yii\log\FileTarget',
'levels' => ['error', 'warning'],
],
],
],
'db' => require(__DIR__ . '/db.php'),
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'rules' => [
[
'class' => 'yii\rest\UrlRule',
'controller' => 'rest\user',
'except' => ['delete', 'create', 'update', 'index'],
'extraPatterns' => [
'GET all' => 'all',
]
],
[
'class' => 'yii\rest\UrlRule',
'controller' => 'rest\auth',
'extraPatterns' => [
'POST reg' => 'reg',
'POST auth' => 'auth',
'POST rest/auth' => 'auth',
],
'pluralize' => false,
],
[
'class' => 'yii\rest\UrlRule',
'controller' => 'rest\city',
'extraPatterns' => [
'DELETE {id}' => 'delete',
],
],
],
],
'i18n' => [
'translations' => [
'*' => [
'class' => 'yii\i18n\PhpMessageSource',
// 'basePath' => '#app/messages', // if advanced application, set #frontend/messages
'sourceLanguage' => 'en',
'fileMap' => [
//'main' => 'main.php',
],
],
],
],
],
'modules' => [
'admin' => [
'class' => 'app\modules\admin\Module',
],
'manager' => [
'class' => 'app\modules\manager\Module',
],
'rest' => [
'class' => 'app\modules\rest\Module',
],
'rbac' => [
'class' => 'mdm\admin\Module',
'controllerMap' => [
'assignment' => [
'class' => 'mdm\admin\controllers\AssignmentController',
/* 'userClassName' => 'app\models\User', */
'idField' => 'id',
'usernameField' => 'username',
],
],
'layout' => 'left-menu',
'mainLayout' => '#app/views/layouts/admin.php',
]
],
'aliases' => [
//'#mdm/admin' => 'app/mdm/admin',
],
'params' => $params,
];
if (YII_ENV_DEV) {
// configuration adjustments for 'dev' environment
$config['bootstrap'][] = 'debug';
$config['modules']['debug'] = [
'class' => 'yii\debug\Module',
// uncomment the following to add your IP if you are not connecting from localhost.
//'allowedIPs' => ['127.0.0.1', '::1'],
];
$config['bootstrap'][] = 'gii';
$config['modules']['gii'] = [
'class' => 'yii\gii\Module',
// uncomment the following to add your IP if you are not connecting from localhost.
//'allowedIPs' => ['127.0.0.1', '::1'],
];
}
return $config;
My Module.php code(commented code shows my attempt to write urlManager):
<?php
namespace app\modules\rest;
/**
* rest module definition class
*/
class Module extends \yii\base\Module
{
/**
* #inheritdoc
*/
public $controllerNamespace = 'app\modules\rest\controllers';
/**
* #inheritdoc
*/
public function init()
{
parent::init();
// custom initialization code goes here
\Yii::$app->user->enableSession = false;
$config = [
'components' => [
'basePath' => dirname(__DIR__),
// 'user' => [
// 'identityClass' => 'app\models\User',
// 'class' => 'app\models\User',
// 'enableSession' => false
// ],
// 'urlManager' => [
// 'enablePrettyUrl' => true,
// 'enableStrictParsing' => true,
// 'showScriptName' => false,
// 'rules' => [
// [
// 'class' => 'yii\rest\UrlRule',
// 'controller' => 'rest\city',
// 'extraPatterns' => [
// 'DELETE {id}' => 'delete',
// ],
// ],
// ],
// ],
'response' => [
'format' => \yii\web\Response::FORMAT_JSON,
'charset' => 'UTF-8',
'class' => 'yii\web\Response',
'on beforeSend' => function ($event) {
$response = $event->sender;
if(( $response->statusCode >= 200) && ( $response->statusCode < 300)) {
if(isset($response->data['_appErr'])) {
unset($response->data['_appErr']);
$response->data = [
'success' => false,
'error' => $response->data,
'data' => null,
];
} else {
$response->data = [
'success' => $response->isSuccessful,
'error' => null,
'data' => $response->data,
];
}
} else {
if($response->statusCode == 401) {
$response->data = [
'success' => false,
'error' => [
'code' => 9,
'message' => 'Unauthorized',
'user_msg' => 'You need to be authorized',
],
'data' => null,
];
}
// else {
// $response->data = [
// 'success' => false,
// 'error' => [
// 'code' => 1,
// 'message' => 'server has returned '.$response->statusCode.' error',
// ],
// 'data' => null,
// ];
// }
}
},
],
],
];
\Yii::configure(\Yii::$app, $config);
}
}
Try this:
namespace yii\rest;
class UrlRule extends Object implements UrlRuleInterface {
public function parseRequest($manager, $request) {
list($e1, $e2) = sscanf($request->getPathInfo(), '%[a-zA-Z]/%[a-zA-Z]');
if ($e1 === 'auth' && $e2 === '') {
return ['/auth/auth', $request->queryParams];
}
return false;
}
}
Use forward slash(/) while defining the controller value in the rules array.
This will work:
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'rules' => [
[
'class' => 'yii\rest\UrlRule',
'controller' => 'rest/user',
'except' => ['delete', 'create', 'update', 'index'],
'extraPatterns' => [
'GET all' => 'all',
]
],
[
'class' => 'yii\rest\UrlRule',
'controller' => 'rest/auth',
'extraPatterns' => [
'POST reg' => 'reg',
'POST auth' => 'auth',
],
'pluralize' => false,
],
[
'class' => 'yii\rest\UrlRule',
'controller' => 'rest/city',
'extraPatterns' => [
'DELETE {id}' => 'delete',
],
],
]
Check out the documentation here: http://www.yiiframework.com/doc-2.0/guide-rest-versioning.html

yii2 captcha image doesn't show

i have the following code in yii2 but the captcha image doesn't show !
controller:
public function actions() {
return [
'captcha' => [
'class' => 'yii\captcha\CaptchaAction',
'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null,
'foreColor' => 0xF9AF21,
'maxLength' => 5,
'minLength' => 3,
'padding' => 5,
'offset' => 1,
'transparent' => true,
'height' => 40
],
'error' => [
'class' => 'yii\web\ErrorAction',
],
];
}
model :(rules)
['verifyCode', 'captcha',],
view:
$form->field($model, 'verifyCode')->widget(Captcha::className()])
In SiteController look for behaviors() function, it might look like in the example bellow.
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'only' => ['logout', 'signup'],
'rules' => [
[
'actions' => ['signup'],
'allow' => true,
'roles' => ['?'],
],
[
'actions' => ['logout'],
'allow' => true,
'roles' => ['#'],
],
],
],
];
}
You will not see captcha image, if in your behaviour() function wouldn't be specified 'only' actions, like this: 'only' => ['logout', 'signup'],. This line says that apply access rules only to this actions. If you don't want to add rules to specific actions, you can add 'captcha' action to your rules, like in example below.
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'rules' => [
[
'actions' => ['signup', 'captcha'],
'allow' => true,
'roles' => ['?'],
],
[
'actions' => ['logout'],
'allow' => true,
'roles' => ['#'],
],
],
],
];
}
Controller:
public function actions()
{
return [
'error' => [
'class' => 'yii\web\ErrorAction',
],
'captcha' => [
'class' => 'yii\captcha\CaptchaAction',
'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null,
'foreColor' => 115006,
'backColor' => 333333,
'height' => 30,
'maxLength' => 4,
'minLength' => 4,
'offset' => 2,
'testLimit' => 1,
],
];
}
Model:
public function rules()
{
return [
['verifyCode', 'captcha'],
];
}
View:
use yii\captcha\Captcha;
<?= $form->field($model, 'verifyCode')->widget(Captcha::classname()) ?>
remove this function in site controller and the problems solved:
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'rules' => [
[
'actions' => ['login', 'error'],
'allow' => true,
],
[
'actions' => ['logout', 'index'],
'allow' => true,
'roles' => ['#'],
],
],
],
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'logout' => ['post'],
],
],
];
}

Categories