. NET Core 3.1, Vue, Ax ios и [ValidateAntiForgeryToken] - PullRequest
2 голосов
/ 03 мая 2020

Я играл с этим весь день и читал столько, сколько мог, и мне совершенно не удалось заставить это работать.

Я сравнил свою реализацию с документацией MS и другими ответами вокруг ТАК и ни один из подходов, похоже, не работает.

Проблема root заключается в переходе от анонимного пользователя и вошедшего в систему пользователя.

Я следую совету MS здесь . И различные ответы здесь и здесь

Для тестирования у меня есть одна контактная форма с конечной точкой, украшенной [ValidateAntiForgeryToken].

Поток:

Посетите сайт, опубликуйте эту форму и все отлично работает. Вход в систему Посетите форму, отправьте сообщение - BOOM - Предоставленный токен защиты от подделки был предназначен для пользователя, основанного на утверждениях, отличного от текущего пользователя.

В моем методе public void Configure( у меня есть:

app.Use(async (context, next) =>
{
        var tokens = antiforgery.GetAndStoreTokens(context);
        context.Response.Cookies.Append("CSRF-TOKEN", tokens.RequestToken, new CookieOptions { HttpOnly = false });

    await next();
});

В моем public void ConfigureServices( методе у меня есть:

services.AddAntiforgery(options => options.HeaderName = "X-CSRF-TOKEN");

В моем Vue Маршрутизаторе я добавил вызов к методу на моем топоре ios API следующим образом:

router.afterEach((to, from) => {
    api.readCsrfCookieAndSetHeader();
});

Этот метод просто читает повар ie и обновляет заголовок:

public readCsrfCookieAndSetHeader() {
    console.info('READING CSRF-TOKEN');
    if (document.cookie.indexOf('CSRF-TOKEN') > -1) {
        const v = document.cookie.match('(^|;) ?' + 'CSRF-TOKEN' + '=([^;]*)(;|$)');
        const r = v ? v[2] : '';
        // console.log(r);
        this.csrfToken = r;
        axios.defaults.headers.common['X-CSRF-TOKEN'] = this.csrfToken;
        console.log(axios.defaults.headers.common['X-CSRF-TOKEN']);
    } else {
        this.csrfToken = '';
    }
}

Я вижу, как это значение изменяется постранично. Одно из предложений, которое, похоже, сработало для некоторых, - это перезапустить GetAndStoreTokens в том месте, где пользователь выполнил вход, например:

var user = await _userManager.FindByEmailAsync(userName);
var result = await _signInManager.PasswordSignInAsync(user, password, true, false);
_httpContextAccessor.HttpContext.User = await _signInManager.CreateUserPrincipalAsync(user);
if (result.Succeeded)
{
    // get, store and send the anti forgery token
    AntiforgeryTokenSet tokens = _antiforgery.GetAndStoreTokens(_httpContextAccessor.HttpContext);
    _httpContextAccessor.HttpContext.Response.Cookies.Append("CSRF-TOKEN", tokens.RequestToken, new CookieOptions { HttpOnly = false });
}

return result;

Но у меня это тоже не сработало.

Я также пытался обновить значение с помощью перехватчика ax ios, например:

axios.interceptors.response.use(
    (response) => {
        // this.readCsrfCookieAndSetHeader();
        return response;
    }, 
    (error) => {

Но на самом деле это просто еще один способ обновить значение, которое, я уверен, уже обновляется.

У меня закончились идеи и, кажется, есть что попробовать. Отсюда этот вопрос.

Я что-то упустил очевидное? Кажется, я почти дословно воспроизвел пример MS Angular, поэтому я не понимаю, что я сделал неправильно.

Любые указатели будут очень признательны.

1 Ответ

2 голосов
/ 04 мая 2020

Как обсуждено в комментариях к вашему вопросу. У меня есть финт памяти о том, что это связано с упорядочением чего-либо в AppStartup. Вот дамп того, что у меня есть. Это в настоящее время работает (кажется, хорошо).

    /// <summary>
    /// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    /// </summary>
    /// <param name="app">The <see cref="IApplicationBuilder"/>.</param>
    /// <param name="env">The <see cref="IHostingEnvironment"/>.</param>
    /// <param name="antiforgery">Enables setting of the antiforgery token to be served to the user.</param>
    public void Configure(IApplicationBuilder app, IHostingEnvironment env, IAntiforgery antiforgery)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions
            {
                HotModuleReplacement = true,
            });
        }

        app.UseSession();

        app.UseHttpsRedirection();

        app.UseStaticFiles();

        // global cors policy
        app.UseCors(x => x
            .AllowAnyOrigin()
            .AllowAnyMethod()
            .AllowAnyHeader());

        // Authenticate before the user accesses secure resources.
        app.UseAuthentication();

        app.Use(next => context =>
        {
            string path = context.Request.Path.Value;
            if (path.IndexOf("a", StringComparison.OrdinalIgnoreCase) != -1 || path.IndexOf("b", StringComparison.OrdinalIgnoreCase) != -1)
            {
                // The request token can be sent as a JavaScript-readable cookie,
                // and Angular uses it by default.
                var tokens = antiforgery.GetAndStoreTokens(context);
                context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken, new CookieOptions() { HttpOnly = false });
            }

            return next(context);
        });

        app.Use(next => context =>
        {
            string timezone = context.Request.Headers["Timezone"];

            if (!string.IsNullOrEmpty(timezone))
            {
                context.Session.SetString(nameof(HttpContextSessionValues.SessionStrings.Timezone), timezone);
            }

            return next(context);
        });

        app.UseExceptionHandler(errorApp =>
        {
            errorApp.Run(async context =>
            {
                context.Response.StatusCode = 500;
                context.Response.ContentType = "text/html";

                var exHandlerFeature = context.Features.Get<IExceptionHandlerFeature>();
                var exception = exHandlerFeature.Error;

                if (exception is PresentableException)
                {
                    await context.Response.WriteAsync(exception.Message).ConfigureAwait(false);
                }
                else
                {
                    await context.Response.WriteAsync("An Unexpected error has occured. You may need to try again.").ConfigureAwait(false);
                }
            });
        });
        app.UseHsts();

        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");

            routes.MapSpaFallbackRoute(
                name: "spa-fallback",
                defaults: new { controller = "Home", action = "Index" });
        });
    }
...