Skip to content

Commit

Permalink
Fix resubmit for cached csrf token by using esi for cacheable request…
Browse files Browse the repository at this point in the history
…s only (#286)

* Fix resubmit for cached csrf token by avoid esi

* Apply suggestions from code review

Co-authored-by: nnatter <niklas.natter@gmail.com>
Co-authored-by: Prokyonn <daniel.mathis@sector8.eu>

Co-authored-by: nnatter <niklas.natter@gmail.com>
Co-authored-by: Prokyonn <daniel.mathis@sector8.eu>
  • Loading branch information
3 people committed Apr 21, 2021
1 parent 5e6f116 commit 31fbd35
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 8 deletions.
54 changes: 50 additions & 4 deletions Resources/doc/csrf.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,22 @@ behaviour of token generation or use the `@SuluForm/themes/basic.html.twig` them

## Ajax

A simplified version loading the csrf token over ajax could
look like this:
> This solution is required when pages are cached using `Varnish`:
```yaml
# config/routes/sulu_form.yaml

sulu_form.token:
path: /form/token
path: /_form/token
defaults:
_controller: Sulu\Bundle\FormBundle\Controller\FormTokenController::tokenAction
_requestAnalyzer: false
```

### A. Ajax with jquery

A simple example for loading the csrf token over ajax looks like this:

```twig
# your-theme.html.twig
Expand All @@ -48,7 +51,50 @@ sulu_form.token:
```

```js
jQuery.get('/form/token?form=' + formName + '&html=0').done(function(data) {
jQuery.get('/_form/token?form=' + formName + '&html=0').done(function(data) {
jQuery('#' + fieldId).val(data);
});
```

### B. Ajax with sulu web-js

When using [`@sulu/web`](https://github.com/sulu/web-js) / [`sulu/web-twig`](https://github.com/sulu/web-twig) component library, loading the csrf token over ajax looks like this:

```twig
{# templates/form/your-theme.html.twig #}
{% extends '@SuluForm/themes/basic.html.twig' %}
{%- block csrf_token_widget -%}
{{ block('hidden_widget') }}
{% do register_component('csrf-token', { id: id, formName: form.parent.vars.name }) %}
{% endblock %}
```

```js
// assets/website/js/componenes/csrf-token.js

export default class CsrfToken {
initialize(el, options) {
fetch('/_form/token?form=' + options.formName + '&html=0').then((response) => {
if (!response.ok) {
return Promise.reject(response);
}

return response.text();
}).then((data) => {
el.value = data;
});
}
}
```

```js
// assets/website/js/main.js

import web from '@sulu/web';
import CsrfToken from './components/csrf-token';

web.registerComponent('csrf-token', CsrfToken);
```
18 changes: 14 additions & 4 deletions Resources/views/themes/basic.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,23 @@
{%- endif -%}
{%- endblock form_label -%}

{# CSRF Token over ESI #}
{# CSRF Token #}
{%- block csrf_token_widget %}
{{ render_esi(controller('Sulu\\Bundle\\FormBundle\\Controller\\FormTokenController::tokenAction', {
{% set controller = controller('Sulu\\Bundle\\FormBundle\\Controller\\FormTokenController::tokenAction', {
'form': form.parent.vars.name,
'html': true,
_requestAnalyzer: false }))
}}
_requestAnalyzer: false
}) %}

{#
If a request is cacheable, the CSRF token must be loaded over ESI to allow for caching the response.
If a request is not cacheable (eg. POST request), we can directly render it.
#}
{% if app.request.isMethodCacheable %}
{{ render_esi(controller) }}
{% else %}
{{ render(controller) }}
{% endif %}
{%- endblock csrf_token_widget -%}

{# Headline #}
Expand Down

0 comments on commit 31fbd35

Please sign in to comment.