Asp.net core 2 + Antiforgery:所有POST端点都返回400 Bad Request

时间:2018-04-05 11:02:18

标签: c# docker asp.net-core asp.net-core-2.0 antiforgerytoken

我有一个带有自定义IXmlRepository的asp.net核心2.1.4应用程序,用于使用ef core + postgres存储应用程序密钥。我使用Docker部署应用程序。

除了在生产中运行时所有POST请求都返回400错误的请求响应外,所有内容都部署并运行正常。一切都很好。

问题与防伪/数据保护设置的设置有关,我认为

当我配置DataProtection和Antiforgery时,这是我的Startup.cs。我已将其编辑得最小,以防万一其他设置可能会干扰。

public class Startup
{
    IHostingEnvironment _env;

    public Startup(IConfiguration configuration, IHostingEnvironment env)
    {
        Configuration = configuration;
        _env = env;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<AppDbContext>(options =>
            options.UseNpgsql(Configuration.GetConnectionString("DefaultConnection"))
        );

        services.AddIdentity<User, Role>()
        .AddEntityFrameworkStores<AppDbContext>()
        .AddDefaultTokenProviders();

        services.Configure<IdentityOptions>(options =>
        {
            // Password settings
            options.Password.RequireDigit = true;
            options.Password.RequiredLength = 8;
            options.Password.RequireNonAlphanumeric = false;
            options.Password.RequireUppercase = true;
            options.Password.RequireLowercase = false;
            options.Password.RequiredUniqueChars = 6;

            // Lockout settings
            options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(30);
            options.Lockout.MaxFailedAccessAttempts = 10;
            options.Lockout.AllowedForNewUsers = true;

            // User settings
            options.User.RequireUniqueEmail = true;
        });

        ### HERE I SET THE CUSTOM KEY STORE ###

        services.AddSingleton<IXmlRepository, EfXmlRepository>();
        var sp = services.BuildServiceProvider();
        services.AddDataProtection()
                .AddKeyManagementOptions(options => options.XmlRepository = sp.GetService<IXmlRepository>());

        services.AddMvc(options =>
        {
            options.OutputFormatters.Add(new HtmlOutputFormatter());
            options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
        });

        ### HERE I SET THE ANTI FORGERY HEADER FOR SOME API CALLS ###

        services.AddAntiforgery(x => x.HeaderName = "X-XSRF-TOKEN");

        services.AddAuthentication()
        .AddCookie()         
        .AddJwtBearer(options =>
        {
            options.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuer = true,
                ValidateAudience = true,
                ValidateIssuerSigningKey = true,
                ValidIssuer = "myapp.com",
                ValidAudience = "myapp.com",
                RequireExpirationTime = false,
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["SecurityKey"]))
            };
        });;

        services.AddTransient<JwtService>();
        services.AddTransient<PaymentProviderService>();
        services.AddTransient<SubscriptionService>();
        services.AddTransient<IInvalidJwtTokenStore, EfInvalidJwtTokenStore>();

        //setup hangfire
        GlobalConfiguration.Configuration.UsePostgreSqlStorage(Configuration.GetConnectionString("DefaultConnection"));

    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
        }

        app.UseStaticFiles();
        app.UseAuthentication();

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

        loggerFactory.AddConsole(LogLevel.Information);
    }

这是我的ef核心IXmlRepository实现:

public class EfXmlRepository : IXmlRepository
{
    AppDbContext _db;

    public EfXmlRepository(AppDbContext dbContext)
    {
        _db = dbContext;
    }

    public IReadOnlyCollection<XElement> GetAllElements()
    {
        var list = _db.XmlKeys.ToList().Select(x => XElement.Parse(x.Xml)).ToList();
        return list;
    }

    public void StoreElement(XElement element, string friendlyName)
    {
        _db.XmlKeys.Add(new XmlKey
        {
            Xml = element.ToString(SaveOptions.DisableFormatting)
        });

        _db.SaveChanges();
    }
}

日志的早期阶段告诉我:

2018-04-04T18:05:58.950344099Z app[web.1]: fail: 
Microsoft.AspNetCore.Antiforgery.Internal.DefaultAntiforgery[7]
2018-04-04T18:05:58.950392982Z app[web.1]:       An exception was 
thrown while deserializing the token.
2018-04-04T18:05:58.950398037Z app[web.1]: 
System.InvalidOperationException: The antiforgery token could not be 
decrypted. ---> System.Security.Cryptography.CryptographicException: 
The key {9b8ab2d0-3ca5-4fcd-af54-b1a6601077af} was not found in the key 
ring.

但是当我调整了IXmlRepository的postgres设置时,这个错误就消失了。

以防这是我的Dockerfile

FROM microsoft/dotnet:latest
COPY . /app
WORKDIR /app

ENV ASPNETCORE_URLS http://0.0.0.0:5000
ENV ASPNETCORE_ENVIRONMENT Production
EXPOSE 5000

RUN dotnet restore
RUN dotnet publish -c Release

WORKDIR /app/MyApp.Web
RUN dotnet ef database update

WORKDIR /app/MyApp.Web/bin/Release/netcoreapp2.0/publish
ENTRYPOINT dotnet MyApp.Web.dll

期待听到你的想法。谢谢!

0 个答案:

没有答案