I'm creating an application using Vue.js and CakePHP 3.6.
When POST, security component throws a 400 error because the _Token fields are missing. I don't have problems with CSRF token, just form security validation.
I don't wanna disable the component in the whole application.
I found a non-solution: Expose _buildFieldToken from the Cake\View\Helper\SecureFieldTokenTrait but I think this will avoid the SecurityComponent purpose.
Any help are really welcome and appriciated.
The action in the controller (example: ajaxRequest) that you need access by fetch or axios, could be unlocked, in the controller:
if you have generated the form with the cake helpers, the _CSRFTOKEN is in the form label or hidden input (sorry inspect the Form element in the browser), when you have localized the token, add this in the data of .$post().
ajax request cakephp
public function beforeFilter(Event $event)
{
//this line is not necessary if you pass the _csrfToken
$this->getEventManager()->off($this->Csrf);
$this->Security->setConfig('unlockedActions', ['ajaxRequest']);
}
Related
I have been working on a simple Laravel Inertia Vue3 application. It has one resource route.
Route::resource('contact', \App\Http\Controllers\ContactController::class);
This provides the named routes contact.index .store .create .show .update .destroy and .edit
Nice and simple so far.
I have a useForm form variable in my Vue component with some assigned variables
let form = useForm({ ... });
I have a submit method in the same component
let submit = () => {
if(props.edit) {
form.patch(`/contact/${props.contact.id}`);
} else {
form.post(`/contact`);
}
}
Again nothing complex. The post method fires off correctly and redirects
Contact::query()->create($request->all());
return redirect()->to(route('contact.index'));
For full disclosure of the update method, please see below:
public function update(Request $request, Contact $contact): \Illuminate\Http\RedirectResponse
{
$contact->fill($request->all())->save();
return redirect()->to(route('contact.show', ['contact' => $contact]));
}
This works in the same way as store. Simple and then redirects... but it doesn't.
What happens is that it runs the patch and then calls redirect
The redirect carries the patch method through ending up with a 405 if I use the index route (declared as get). If I use back() I get the same thing. If I use the show route, it redirects in a loop because the patch route uses the same URL /contact/{contact}
I have built Laravel applications for the last 5 years and have not had an issue like this before when using a named route. Have I missed something basic? If not its possibly a configuration issue although I am not sure what.
I am running Laravel 9.19 with webpack manually installed as its been changed to Vite on the current release. I have no Vue errors or warnings and no Laravel logs.
there is a difference between PUT and PATCH requests on laravel-level.
Please run php artisan route:list - and see which one is used in your case, There is a big chance that you using PUT, not patch :)
So good ol' Laravel got me again.
Alexander Dyriavin got me on the right course with his answer about put and patch, however, it wasn't really the solution.
The solution:
form.transform((data) => ({
...data,
_method: 'PUT' //spoof added to request
})).post(`/contact/${props.contact.id}`); //sent as a post instead
The Laravel docs allow you to spoof methods https://laravel.com/docs/5.0/routing#method-spoofing by posting them with a _method field.
Simply put, a patch or put request would have always failed with a redirect from Laravel. In the past I would have used them with Axios and handled a JSON response directly.
This time I really am answering my own question.
I was a total idiot and missed a step when setting up inertia js. I was attempting to retrieve errors with the useform method and what happened was I received nothing.
So I though I would double check the docs.
Turns out I missed adding this middleware to the web middleware group in the kernel!
\App\Http\Middleware\HandleInertiaRequests::class,
I can now use the .patch method I had before and no need for any additional code
I'm trying to implement private channel authorization with Pusher and Laravel.
The forms require a CSRF input field (randomized input name and value). Normally I use twig to insert them into the forms I put on the page.
How can I insert the csrf fields into the form data that Pusher sends when it tries to connect to the auth endpoint? It isn't present in the form data (but is present in the request header), so it's getting rejected by the laravel CSRF middleware.
If you're using Laravel, this isn't necessary, you shouldn't implement your auth endpoint like this. Your auth endpoint should be defined inside channels.php in the routes folder. For example
// routes/channels.php
Broadcast::channel('chat', function ($user) {
return Auth::check();
});
CSRF not necessary.
I've been reading about the crsf protection in codeigniter, but I can't seem to find a decent tutorial on how to proceed after enabling csrf in the config file.
I have a form generated by a controller function users/create that submits to another function users/submit_new.
I used the form helper class so that the crsf field is automatically generated.
I have this validation function on the submit function:
if ($this->input->post(get_csrf_token_name()) == get_csrf_hash()) {
$this->users_model->create(); }
But all I get is action not allowed error.
What is the right way to validate csrf? Or am I doing something wrong?
If you're using CodeIgniter CSRF the way the user guide mentions, by setting:
$config['csrf_protection'] = TRUE; // this in application/config/config.php
And you are also using the form helper to generate your form open tag, then you do not need to check for the token and hash the way you are doing. CodeIgniter does this for you.
Read the docs: https://www.codeigniter.com/user_guide/libraries/security.html#cross-site-request-forgery-csrf
If you still have problems, then see related questions:
codeigniter CSRF error: "The action you have requested is not allowed."
Action you have requested is not allowed error
I have a cached site which have a form in it which should not be cached. I use ESI for it. When the form is submit I need to get the POST Parameter in my controller. Symfony let me get the Request Parameter 'form' not the real POST Data or is there a good way to get them.
{{ render_esi(controller('MyBundle:Form:staticForm', {'form': 'sidebar'}))}}
Setting them in twig will not work because of Parent Page Cache.
{{ render_esi(controller('MyBundle:Form:staticForm', {'form': 'sidebar', 'request': }))}}
So how to get the post parameter in my controller currently the code shown here only gets me the ESI data:
public function staticFormAction(Request $request) {
// ..
$form->handleRequest($request);// will not work because:
$request->get('firstName'); // is empty when called by ESI
How I can get the Parameters from the Parent Request?
Hacky solution
Currently the only solution I found is for me too hacky
TWIG:
{{ render_esi(controller('ClientWebsiteBundle:Form:staticForm', app.request.request.all|merge({'form': 'sidebar'}), app.request.query.all)) }}
PHP:
$data = ($request->get('myFormName'));
if (count($data)) {
// Forms uses $request->request
$request->request->set('myFormName', $data);
$request->setMethod('POST');
}
Additional
After a little research and look into symfony core code I need to change the ESI to Post so my question is know "How to call ESI as POST method not GET?"
Solution
Using requestStack like Chris Tickner posted seems the post solution.
ESI is an edge-side include, which means it is not designed to handle POST data. By default, reverse proxies like Varnish or Symfony's HttpCache kernel, see the ESI as a URL ("/_proxy?_controller=x¶ms=etc") which they include by GET-ing it from your app. This is why you are finding this difficult.
However, no proxy is going to cache a POST request, so you could, during a POST request, access the master request using the request_stack service.
// if POST
$master_request = $this->get('request_stack')->getMasterRequest();
$form->handleRequest($master_request);
This should do the trick if you are using the Symfony HttpCache.
http://api.symfony.com/2.7/Symfony/Component/HttpFoundation/RequestStack.html
You can get the full form data using
$data = $form->getData();
Or, for single fields:
$var = $form->get('yourformfieldname')->getData();
Watch out: this is for Symfony >= 2.3, and it would get you two different things:
the entity with values populated by the form, if your form have the data-class option enabled (so it's binded to an entity); this will exclude any field with the 'mapping' => false option
otherwise, an array with all the form's fields
Background: I'm using Symfony Forms and Symfony Validation components to render a form in my applications registration page in my Silex application.
I have the form working correctly, rendering, client side validation and binding data to my entities. I've added a validation method to the entity which correctly validates the entity and produces the expected errors.
Question: I now want to get the errors out of the returned ConstraintValidationList and back into the form to display them on the front end using the twig {{ form_errors }} view helper.
I've consulted the API docs at: http://api.symfony.com/2.0/Symfony/Component/Form/Form.html and can't see the correct method for doing this. Does anyone know how to achieve what I'm looking for?
Here is the code from my Silex controller closure:
$app->post('/register-handler', function(Request $request) use($app)
{
// Empty domain object
$user = new MppInt\Entity\User();
// Create the form, passing in a new form object and the empty domain object
$form = $app['form.factory']->create(new MppInt\Form\Type\RegisterType(), $user);
// Bind the request data to the form which puts it into the underlying domain object
$form->bindRequest($request);
// Validate the domain object using a set of validators.
// $violations is a ConstraintValidationList
$violations = $app['validator']->validate($user);
// Missing step - How do I get a ConstraintValidationList back into the
// form to render the errors in the twig template using the {{ form_errors() }}
// Helper.
});
At the bind request stage validators should be run on the data so you shouldn't need to use the validation service yourself. (Coming from Sf2 rather than Silex the validator service is associated with Form I don't know if you have to do this manually for Silex)
Unless error bubbling is enabled on each field the errors will be held in the fields (children) of the form for displaying errors using {{ form_errors() }}
Although if you really need to get a constraintViolationList into a form errors, you can convert them into Symfony\Component\Form\FormError objects and add them to the form with $form->addError(FormError $formError);