AntiForgeryToken dla Fetch?

0

Hej, posiadam kontroler:

[Route("comments/new")]
        public ActionResult AddComment(Survey survey)
        {
            if (survey == null)
            {
                return BadRequest();
            }
            survey.Time = DateTime.Now;
            _context.Surveys.Add(survey);
            _context.SaveChanges();

            return Ok();
        }

przez który Fetch zapisuje query:

const queryParams = `Name=${this.state.surveyState.name}&Change=${this.state.surveyState.change}&Opinion=${this.state.surveyState.opinion}`;
                    fetch(`/comments/new?${queryParams}`)
                        .then(res => res.json())
                        .then(res => {
                            console.log(res);
                        })
                        .catch(error => {
                            console.error(error);
                        });

Czy jest jakiś sposób, aby dodać do Fetch token, jak to się robi w przykładzie dla AJAX w przykładzie:
https://stackoverflow.com/questions/14473597/include-antiforgerytoken-in-ajax-post-asp-net-mvc

?

2

Pewnie że jest, tutaj masz jak dodać token:
Use fetch() to POST JSON-encoded data.
w body dodajesz token analogicznie jak w jquery data, plus trzeba dołączyć ciasteczko:
Sending a request with credentials included

0
neves napisał(a):

Pewnie że jest, tutaj masz jak dodać token:
Use fetch() to POST JSON-encoded data.
w body dodajesz token analogicznie jak w jquery data, plus trzeba dołączyć ciasteczko:
Sending a request with credentials included

Dziękuję, tego mi było trzeba. Niestety pojawia się problem. Aktualnie moje żądanie Fetch (jeszcze przed dodaniem tokenów) wygląda następująco:

const queryParams = `Name=${this.state.surveyState.name}&Change=${this.state.surveyState.change}&Opinion=${this.state.surveyState.opinion}`;
                    fetch(`/comments/new?`,
                        {
                            method: 'POST',
                            body: JSON.stringify({ queryParams }), // data can be `string` or {object}!
                            headers: { 'Content-Type': 'application/json' },
                            credentials: 'include'
                        }
                    )
                        .then(res => res.json())
                        .then(res => {
                            console.log(res);
                        })
                        .catch(error => {
                            console.error(error);
                        });

Metoda kontrolera, po dodaniu [HttpPost]:

[HttpPost]
        [Route("comments/new")]
        public ActionResult AddComment(Survey survey)
        {
            if (survey == null)
            {
                return BadRequest();
            }
            survey.Time = DateTime.Now;
            _context.Surveys.Add(survey);
            _context.SaveChanges();

            return Ok();
        }

Nie uderza mi w żaden break point. Po wysłaniu żądania Fetch XHR konsoli pówi mi, że metoda żądania to GET:

URL żądania: http://localhost:58256/comments/new?Name=sss&Change=sss&Opinion=good
Metoda żądania: GET
Zdalny adres: [::1]:58256
Kod stanu: 404 Not Found
Wersja: HTTP/1.1

Oczywiście i bez [HttpPost] daje mi to samo, jedynie kod stanu się zmienia.

0

@UPDATE:

Z jakiegoś powodu, przy zmianie
fetch(/comments/new?
na
fetch(/Survey/AddComment

XHR podaje mi wciąż tę samą ścieżkę żądania:
http://localhost:58256/comments/new?Name=aaa&Change=aaa&Opinion=good

Cokolwiek nie wpiszę w URL dla fetch, nie zmiania się ona.

EDIT

Po usunięciu [Route("comments/new")] i pozostawieniu fetch("/Survey/AddComment" nie ma żądania wcale.

0

@UPDATE:

zmieniłem kontroler na [Route("comments/new/dupa")] i fetch url na fetch('/comments/new/dupa', i dalej otrzymuję ten sam XHR log dla żądania url co wcześniej, nawet po wyczyszczeniu wszystkich danych przeglądarki i się pytam wtf?

0

Dla potomnych, udało mi się w końcu zaimplementować AntiForgery token dla wywołania Fetch. Było to bardziej kompleksowe zadanie niż się spodziewałem. Też może być inaczej dla różnych wersji ASP.NET. Poniżej rozwiązanie dla ASP.NET Core 2.1.

W Startup.cs dodajemy:

//znalazłem konfigurację w jakimś tutku, już go dawno zamknąłem, czasami można spotkać z X-XSRF-TOKEN, dla tego nie testowałem
public void ConfigureServices(IServiceCollection services)
{
(...)
services.AddAntiforgery(x => x.HeaderName = "X-CSRF-TOKEN");
services.AddMvc();
}
(...)
public void Configure(IApplicationBuilder app, IHostingEnvironment env, IAntiforgery antiforgery)
        {
            (...)
            app.Use(next => context =>
            {
                if (context.Request.Path == "/")
                {
                    //send the request token as a JavaScript-readable cookie
                    var tokens = antiforgery.GetAndStoreTokens(context);
                    context.Response.Cookies.Append("CSRF-TOKEN", tokens.RequestToken, new CookieOptions { HttpOnly = false });
                }
                return next(context);
            });
            app.UseAuthentication();
            app.UseStaticFiles(); //podobno musi być wstawiane przed tym

Moja metoda POST w SurveyController.cs wygląda tak:

[HttpPost]
        [ValidateAntiForgeryToken]
        public IActionResult AddComment(Survey survey)
        {
            if (survey == null)
            {
                return BadRequest();
            }
            survey.Time = DateTime.Now;
            _context.Surveys.Add(survey);
            _context.SaveChanges();

            return Ok();
        }

W pliku JS, u mnie Dialog.js należy dodać funkcję pobierającą ciasteczka:

//podobnie jak w tutorialu https://www.w3schools.com/js/js_cookies.asp
function getCookie(name) {
    if (!document.cookie) {
        return null;
    }
    const csrfCookies = document.cookie.split(';')
        .map(c => c.trim())
        .filter(c => c.startsWith(name + '='));
    if (csrfCookies.length === 0) {
        return null;
    }
    return decodeURIComponent(csrfCookies[0].split('=')[1]);
}

następnie przy odpaleniu Fetch:

var csrfToken = getCookie("CSRF-TOKEN");
                    //url dla fetch, rekonemdowany sposób w dokumentacji
                    var url = new URL("http://localhost:58256/Survey/AddComment"),
                        params = { Name: this.state.surveyState.name, Change: this.state.surveyState.change, Opinion: this.state.surveyState.opinion };
                    Object.keys(params).forEach(key => url.searchParams.append(key, params[key]));
                    fetch(url,
                        {
                            method: 'POST',
                            headers: {
                                'Content-Type': 'application/json',
                                "X-CSRF-TOKEN": csrfToken //wysyłamy token wraz z żądaniem
                            },
                            contentType: "application/json; charset=utf-8",
                            credentials: 'include'
                        }
                    )
                        .then(res => res.json())
                        .then(res => {
                            console.log(res);
                        })
                        .catch(error => {
                            console.error(error);
                        });

1 użytkowników online, w tym zalogowanych: 0, gości: 1