I have this yii2 controller where I want to set Access-Control-Allow-Origin: * header
class DoctorController extends ActiveController
{
public $modelClass = 'api\modules\v1\models\Doctor';
public function behaviors()
{
$behaviors = parent::behaviors();
$behaviors['access'] = [
'class' => \yii\filters\AccessControl::className(),
'rules' => [
[
// All actions
'allow' => true,
'actions' => ['index', 'view'],
],
],
];
return $behaviors;
}
}
Please Help!
You may use this simple code:
header('Access-Control-Allow-Origin: *');
It may be added into one of your controller's action or into beforeAction() of your Controller or other use case (at your discretion according to the logic/architecture of your application).
https://www.yiiframework.com/doc/api/2.0/yii-base-controller#beforeAction()-detail
I have solved it by updating the behaviors() function
public function behaviors()
{
$behaviors = parent::behaviors();
$behaviors['corsFilter'] = [
'class' => \yii\filters\Cors::className(),
'cors' => [
'Origin' => ['*'],
'Access-Control-Request-Method' => ['GET'], // add more
'Access-Control-Request-Headers' => ['*'],
'Access-Control-Allow-Credentials' => null,
'Access-Control-Max-Age' => 86400,
],
];
$behaviors['access'] = [
'class' => \yii\filters\AccessControl::className(),
'rules' => [
[
// All actions
'allow' => true,
'actions' => ['index', 'view'], // add more
],
],
];
return $behaviors;
}
Related
I have the following in my behaviors
public function behaviors()
{
$behaviors = parent::behaviors();
$auth = $behaviors['authenticator'] = [
'class' => CompositeAuth::className(),
'authMethods' => [
HttpBearerAuth::className(),
QueryParamAuth::className(),
],
'except' => ['login', 'check-token-validity', 'test-accounts'],
];
unset($behaviors['authenticator']);
$behaviors['corsFilter'] = [
'class' => Cors::className(),
'cors' => [
// 'Origin' => ['*'],
'Access-Control-Allow-Credentials' => true,
'Origin' => static::allowedDomains(),
'Access-Control-Request-Method' => ['POST', 'PUT'],
'Access-Control-Expose-Headers' => ['Access_status_code'],
],
];
$behaviors['verbs'] = [
'class' => VerbFilter::className(),
'actions' => [
'delete' => ['POST', 'OPTIONS'],
],
];
$behaviors['authenticator'] = $auth;
//access
return $behaviors;
}
public static function allowedDomains()
{
return [
'http://test1.example.com',
'http://test2.example.com',
];
}
As from the above, I have set origin as the above static domains but when I checked on my ajax request response I found out that the response header origin is set as Access-Control-Allow-Origin: *
Also, I haven't been able to restrict access methods despite setting Access-Control-Request-Method
What else do I need to add for this to work?
I am using frontend module in yii2 framework for my website, and so far the website is working good for all things especially the session of login from web interface.
The model handling the login is the LoginForm model
namespace app\models;
use Yii;
use yii\base\Model;
/**
* Login form
*/
class LoginForm extends Model {
public function login()
{
if ($this->validate()) {
return Yii::$app->user->login($this->getUser(), $this->rememberMe ? 7200 * 24 * 30 : 7200 * 24 * 30);
}
return false;
}
For website the default file for login is in SiteCotroller.php
use yii\web\Controller;
use frontend\models\ContactForm;
/**
* Site controller
*/
class SiteController extends Controller {
/**
* #inheritdoc
*/
public function behaviors() {
return [
'access' => [
'class' => AccessControl::className(),
'only' => ['logout', 'signup', 'index'],
'rules' => [
[
'actions' => ['signup'],
'allow' => true,
'roles' => ['?'],
],
[
'actions' => ['logout', 'index'],
'allow' => true,
'roles' => ['#'],
],
],
],
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'logout' => ['post'],
],
],
];
}
public function actionLogin() {
$this->layout = 'main';
if (!Yii::$app->user->isGuest) {
return $this->goHome();
}
$model = new LoginForm();
if ($model->load(Yii::$app->request->post()) && $model->login()) {
return $this->goBack();
} else {
return $this->render('login', [
'model' => $model,
]);
}
}
}
The login controller is working great for its own interface in the view file.
Now that I want to access login from app (ionic/angular), I copied this controller for login to AppController.php in the similar frontend folder:
class AppController extends \yii\rest\Controller {
public function actions()
{
$actions = parent::actions();
$actions['options'] = [
'class' => 'yii\rest\OptionsAction',
// optional:
'collectionOptions' => ['GET', 'POST', 'HEAD', 'OPTIONS'],
'resourceOptions' => ['GET', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'],
];
return $actions;
}
public function actionIndex() {
echo json_encode("hi");
}
public static function allowedDomains() {
return [
'*', // star allows all domains
'http://localhost:8100',
//'http://test2.example.com',
];
}
public function init()
{
parent::init();
\Yii::$app->user->enableSession = false;
}
public function beforeAction($action)
{
$this->enableCsrfValidation = false;
return parent::beforeAction($action);
}
public function behaviors()
{
$behaviors = parent::behaviors();
unset($behaviors['authenticator']);
// add CORS filter
$behaviors['corsFilter'] = [
'class' => \yii\filters\Cors::className(),
'cors' => [
'Origin' => ['*'],
'Access-Control-Request-Method' => ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'],
'Access-Control-Request-Headers' => ['*'],
'Access-Control-Allow-Credentials' => true,
],
];
$behaviors['contentNegotiator'] = [
'class' => \yii\filters\ContentNegotiator::className(),
'formats' => [
'application/json' => \yii\web\Response::FORMAT_JSON,
],
];
$behaviors['authenticator'] = [
'class' => HttpBearerAuth::className(),
'except' => ['login', 'checkuser'],
/*
'class' => CompositeAuth::className(),
'authMethods' => [
HttpBasicAuth::className(),
],
'except' => ['login', 'checkuser'],
*/
];
return $behaviors;
}
public function actionLogin() {
$model = new LoginForm();
$params = Yii::$app->request->post();
$model->username = $params['username'];
$model->password = $params['password'];
if ($model->login()) {
$user = User::findByUsername($model->username);
$response['success'] = Yii::$app->user->login($user);
$response['SessionID'] = Yii::$app->session->getId();
return $response;
} else {
$response['errors'] = $model->getErrors();
return $response;
}
}
The strange is, the action login in this AppController.php is working if I tried to login from app/postman, it returns true. However, the session is not saved, and SessionID is empty.
I have been exploring this for three days but still cant figure it out what is the problem.
This is my frontend/config/main.php file
$params = array_merge(
require __DIR__ . '/../../common/config/params.php',
require __DIR__ . '/../../common/config/params-local.php',
require __DIR__ . '/params.php',
require __DIR__ . '/params-local.php'
);
return [
'id' => 'app-frontend',
'defaultRoute' => 'site/index',
'basePath' => dirname(__DIR__),
'bootstrap' => ['log', 'gii'],
'controllerNamespace' => 'frontend\controllers',
'layout' => 'admin',
'components' => [
'request' => [
'parsers' => [
'application/json' => 'yii\web\JsonParser',
],
'csrfParam' => '_csrf-frontend',
],
'user' => [
'identityClass' => 'app\models\User',
'enableAutoLogin' => false,
'enableSession' => true,
'identityCookie' => ['name' => '_identity-frontend', 'httpOnly' => true, 'lifetime' => 3600 * 4],
'loginUrl' => ['site/login'],
],
'session' => [
'name' => 'advanced-frontend',
],
When I access the url directly into the yii2 web domain, I got this _csrf-frontend and advanced-frontend value in browser Cookies. But from app I dont get any.
Please I really appreciate the help. Many thanks in advance.
You cannot retrieve session from another app it is bound to domain. So what should you probably do is to handle that logic separate in your Ionic application which I think is preferred way. Or you can do it by storing sessions in DB (there is Yii class for that) and than handle it through extra requests (which is bad approach).
Problem
Every custom action redirects back to the login page.
My code
I've extended my custom controller from the dektrium\user\controllers\RegistrationController
My web.php
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'rules' => [
],
],
...
'modules' => [
'user' => [
'class' => 'dektrium\user\Module',
'controllerMap' => [
'registration' => 'app\controllers\user\RegistrationController'
],
],
],
Custom controller
namespace app\controllers\user;
use dektrium\user\controllers\RegistrationController as BaseAdminController;
class RegistrationController extends BaseAdminController
{
public function actionPlan()
{
echo 'Test';
}
}
Overrode methods works good, but each custom action (site.com/user/registration/plan) redirects back to the login page.
If you want change the access control rules you should change properly eg: in your site controller add plan to the rules accessible without authenctication
class SiteController extends Controller
{
/**
* #inheritdoc
*/
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'rules' => [
[
'actions' => ['login','plan', 'error'],
'allow' => true,
],
[
'actions' => ['logout', 'index'],
'allow' => true,
'roles' => ['#'],
],
],
],
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'logout' => ['post'],
],
],
];
}
see this for more http://www.yiiframework.com/doc-2.0/guide-security-authorization.html
http://www.yiiframework.com/doc-2.0/yii-filters-accesscontrol.html
Another implementation
class SiteController extends Controller
{
/**
* #inheritdoc
*/
public function behaviors()
{
$behaviors = [
'access' => [
'rules' => [
[
'actions' => ['login', 'plan', 'error'],
'allow' => true,
],
],
],
];
return ArrayHelper::merge($behaviors, parent::behaviors());
}
}
I can trying simple code.
I have an AccessController which having behaviors():
class AccessController extends BackendController
{
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'rules' => [
[
'allow' => true,
'roles' => ['#'],
],
]
],
];
}
/*public function init()
{
parent::init();
if( Yii::$app->getUser()->getIsGuest() )
{
return $this->redirect('/auth');
}
return true;
}*/
public function actions()
{
return [
'WysiwygUpload' => [
'class' => WysiwygUpload::className(),
]
];
}
}
AS I understand, if I didn't declare 'only' key, that is mean to all actions and controllers.
But nothing happen: no one error, nothing
Your controller AccessController work only for yourApp/backend/access request not for all controllerAction..
If you want deny the access to guest in AdminController you shuold apply the behavior of AdminController
class AdminController extends Controller
{
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'rules' => [
[
'allow' => true,
'roles' => ['#'],
],
]
],
];
}
........
Then when a guest try accessing to yourApp/backend/admin this is not permitted
As I know simple authentication for REST like in this guide
public function behaviors()
{
$behaviors = parent::behaviors();
$behaviors['authenticator'] = [
'class' => QueryParamAuth::className(),
];
return $behaviors;
}
But I want provide some rules to handle guest access? like access control from authorization guide like this
$behaviors['access'] = [
'class' => AccessControl::className(),
'rules' => [
// allow authenticated users
[
'allow' => true,
'actions' => ['some-action'],
'roles' => ['?'],
],
[
'allow' => true,
'roles' => ['#'],
],
// everything else is denied
],
];
If I access some_guest_action as guest without access-token, it will be fine,
but if I access with access-token, Yii::$app->user->getId() always return null value
My complete code like this
public function behaviors()
{
$behaviors = parent::behaviors();
$behavior['authenticator'] = [
'class' => QueryParamAuth::className(),
];
$behaviors['access'] = [
'class' => AccessControl::className(),
'rules' => [
// allow authenticated users
[
'allow' => true,
'actions' => ['some-action'],
'roles' => ['?'],
],
[
'allow' => true,
'roles' => ['#'],
],
// everything else is denied
],
];
return $behaviors;
}
public function actionSomeAction()
{
return Yii::$app->user->getId();
}