What's the best way to make a ZF3 application with no default router? - zend-framework-mvc

I made a Zend Framework 3 MVC application. I don't want a default router. My one controller RESTFUL and only returning JSON. I want to remove the default IndexController. I want / to just give a 404 error. I'd prefer not to call any route 'home' but will do that if necessary.
If I make my route config look like this:
'router' => [
'routes' => [
'myRoute' => [
'type' => Segment::class,
'options' => [
'route' => '/myThing[/:action]',
'defaults' => [
'controller' => Controller\MyThingController::class,
'action' => 'index',
],
],
],
],
],
I get the following exception when I connect to a route that worked when I kept the default index controller in my browser:
Fatal error: Uncaught Zend\Router\Exception\RuntimeException: Route with name "home" not found in /var/www/vendor/zendframework/zend-router/src/Http/TreeRouteStack.php on line 354
If I change 'myRoute' => [ to 'home' => [ It renders the default layout instead of the Json rendered by JsonViewModel.

I just put an IndexController with a default route that renders the defautl 404 page for now. I'm going to make it return JSON at some point when I figure out how.
class IndexController extends AbstractRestfulController
{
public function indexAction()
{
$this->response->setStatusCode(Response::STATUS_CODE_404);
}
}

I'm not sure if this is what your after but to return a json response from your controller use.
In your module config:
'view_manager' => array(
'strategies' => array(
'ViewJsonStrategy',
),
},
and in your controller:
use Zend\View\Model\JsonModel;
// ...
public function indexAction()
{
$this->response->setStatusCode(Response::STATUS_CODE_404);
$view = new JsonModel();
$view->jsonVariable = 'someValue';
return $view;
}
This will return a json response.
Hope this helps.

Related

Yii2 : ajax post request always redirect to login page

I'm trying to send data using ajax POST request but I'm always redirected to login page even if I authorize the method to anonymous users (['actions' => ['update', 'test'], 'allow' => true]). When I test with a GET request there is no problem.
My controller :
public function behaviors() {
return [
'access' => [
'class' => AccessControl::className(),
'rules' => [
['actions' => ['update', 'test'], 'allow' => true],
],
],
];
}
public function actionTest() {
Yii::$app->request->enableCsrfValidation = false;
echo 'ok';
}
I use Postman to test requests
The solution you used is not a solution actually, its like if you cant open the lock with a key just remove the lock.
Mostly you get the 400 Bad Request if you are making an Ajax Post request without sending the CSRF parameters, I never faced the problem like being redirected to the login page.
But if your problem is resolved by disabling the CSRF Validation then you should follow this method while making any ajax requests.
In your config, you define the csrf parameter name using csrfParamin the request component like this
'request' => [
'csrfParam' => '_csrf-app',
],
This can be different for you if it is already defined.
You have to send this param _csrf-app with the csrf value in the ajax request along with your post data. and for retrieving the value for the csrf you can use javascript yii.getCsrfToken() method, or Yii::$app->request->csrfToken if in view via php.
See this example call you can hardcode the name of the param _csrf-app or use Yii::$app->request->csrfParam if your script is inside the view file.
$.ajax({
url:'/add',
data:{'_csrf-app':yii.getCsrfToken()}
success:function(data){}
});
Hope this solves your problem.
lubosdz's suggestion solved the problem
Modified controller :
public function behaviors() {
return [
'access' => [
'class' => AccessControl::className(),
'rules' => [
['actions' => ['update', 'test'], 'allow' => true],
],
],
];
}
public function beforeAction($action) {
if ($action->id == 'test') {
$this->enableCsrfValidation = false;
}
return parent::beforeAction($action);
}
public function actionTest() {
echo 'ok';
}
I found a solution that looks a bit like yours Muhammad Omer Aslam : by serializing the form in JavaScript I can send directly all the fields and the csrf token generated by the ActiveForm.
$.ajax({
url: ...,
type: 'POST',
data: $('#myForm').serialize(),
success: (response) => { ... }
})

redirect in before action is running infinitely in yii2

i have added access filter to web.php and in login action consists following code
public function actionLogin() {
return $this->render('loginform', ['model' => $model, 'iv' => $iv, 'key' => $key]);
}
In Yii2 you don't have to do workarounds like that to achieve checking if user is logged in. Yii2 has own Access Controll behaviours, which will do all for you.
To use it, add in your controller this behaviour:
public function behaviors()
{
return [
'access' => [
'class' => yii\filters\AccessControl::className(),
'rules' => [
[
'allow' => true,
'roles' => ['#']
],
],
],
];
}
It will check if user whos trying access all actions in this controller is logged in. For more options you should look here: YIi2 - Access Control Filter

Cakephp goes to wrong path

I am working on Cakephp. In default.ctp i give a link like
<li><?= $this->Html->link('List',['controller' => 'Products', 'action' => 'index']) ?></li>
I also have a ProductsController.php .
<?php
namespace App\Controller;
use Cake\Controller\Controller;
use Cake\Event\Event;
use Cake\ORM\TableRegistry;
class ProductsController extends AppController {
public function initialize(){
parent::initialize();
$this->loadcomponent('Flash');
}
public function index(){
$products = $this->Products->find('all');
$this->set(compact('products'));
}
But when i click on that link it give the error like
Error: WebrootController could not be found.
Error: Create the class WebrootController below in file: src/Controller/WebrootController.php
When click on toggle arguments it shows
object(Cake\Network\Request) {
params => [
'plugin' => null,
'controller' => 'Webroot',
'action' => 'products',
'_ext' => null,
'pass' => [],
'_matchedRoute' => '/:controller/:action/*',
'isAjax' => false
]
data => []
query => []
cookies => [
'__atuvc' => '1|21'
]
url => 'webroot/products/'
base => '/cakephp'
webroot => '/cakephp/'
here => '/cakephp/webroot/products/'
trustProxy => false
Please help me to solve this error.
Check if you have two .htaccess files present in your application root folder and in the webroot folder.
And make sure that an .htaccess override is allowed and that AllowOverride is set to All for the correct DocumentRoot
http://book.cakephp.org/3.0/en/installation.html#url-rewriting

How do I replace the default auth.basic response with a JSON response?

I have a route group that looks like this:
Route::group(['prefix' => 'recipe','middleware'=>['auth.basic']], function (){
//Some things to do
});
When credentials are invalid Laravel outputs "Invalid credentials." How do I override this response with my own JSON response?
In AuthController, try this :
public function postLogin(Request $request)
{
$this->validate($request, [
'email' => 'required', 'password' => 'required',
]);
$credentials = [
'email' => $request->input('email'),
'password' => $request->input('password')
];
if (Auth::attempt($credentials, $request->has('remember')))
{
return redirect()->intended($this->redirectPath())
->with('success', 'You are successfully logged in');
}
return Response::json(array(
'success' => false,
'errors' => $this->getFailedLoginMessage(),
));
}
I just had a look at the Illuminate\Auth\SessionGuard. The method getBasicResponse() seems to be responsible for the response on a failed login attempt (with basic auth).
protected function getBasicResponse()
{
$headers = ['WWW-Authenticate' => 'Basic'];
return new Response('Invalid credentials.', 401, $headers);
}
How to actually overwrite it seems a little tricky though. You probably need to extend the SessionGuard Class and implement your own getBasicResponse() method. Thats the easy part, how to actually instantiate your own guard instead of the default one, I don't know yet.

Redirect user to previous page after auth (yii2)

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' => ['#'],
],
],
],
];
}
// ...
}