ASP.Net Core 2.1 Vue.JS SPA-Cookie身份验证和Vue.JS开发服务器

时间:2019-05-31 18:27:41

标签: c# vue.js asp.net-core-webapi asp-net-core-spa-services

我有一个应用程序,本质上是一个位于dotnet core 2.1应用程序中的Vue.JS SPA,提供API服务。使用当前的Startup.cs配置启动应用程序时,它将启动3个窗口。这些窗口中的1个是实际的ASP.Net Core应用程序根目录-其他2个(不要问我为什么2个)是执行npm run serve时获得的Vue.js开发服务器的副本。

我遇到的问题是,如果我使用在第一个窗口中运行的实例,则身份验证可以正常工作,但是,如果尝试使用Vue.JS服务器窗口登录,则只能返回401。

>

我的第一个想法是CORS,因此我纯粹为在开发模式下运行时设置了CORS策略,但这并没有解决问题。没有Vue.JS服务器进行开发实际上并不可行,因为没有它我就没有HMR,并且每次进行设计更改时都需要重新加载整个应用程序状态。

之前,我已经使用.net Framework 4.6 API后端进行了此设置,一点问题都没有,所以我只能认为这是一种现代的安全性增强功能,它阻止了代理的配置,而我需要在开发或其他方面将其配置为关闭

欢迎提出任何有关如何解决此问题的建议。

这是我当前的Startup.cs配置...

       public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory,
        ApplicationDbContext context, RoleManager<IdentityRole> roleManager, UserManager<ApplicationUser> userManager)
    {
        if (env.IsDevelopment())
        {
            app
                .UseDeveloperExceptionPage()
                .UseDatabaseErrorPage()
                .UseCors("DevelopmentPolicy");
        }
        else
        {
            app
                .UseExceptionHandler("/Home/Error")
                .UseHsts();
        }

        app
            .UseAuthentication()
            .UseHttpsRedirection()
            .UseStaticFiles()
            .UseSpaStaticFiles();

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

        app.UseSpa(spa =>
        {
            spa.Options.SourcePath = "VueApp";

            if (env.IsDevelopment())
            {
                spa.UseVueCliServer("serve");
            }
        });

        DbInitializer.Initialize(context, roleManager, userManager, env, loggerFactory);
    }

...和ConfigureServices ...

   public void ConfigureServices(IServiceCollection services)
    {
        services
            .AddLogging(builder => builder
                .AddConsole()
                .AddDebug());

        services
            .AddMvc()
                .SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
                .AddJsonOptions(options => options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver());

        services
            .AddCors(options =>
            {
                options.AddPolicy("DevelopmentPolicy",
                    policy => policy.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod());
            });

        // In production, the Vue files will be served from this directory
        services.AddSpaStaticFiles(configuration => { configuration.RootPath = "wwwroot"; });
        services.AddAuthentication();

        services
            .ConfigureEntityFramework(Configuration)
            .ConfigureEntityServices()
            .ConfigureIdentityDependencies()
            .ConfigureDomainServices()
            .ConfigureApplicationCookie(config =>
            {
                config.SlidingExpiration = true;
                config.Events = new CookieAuthenticationEvents
                {
                    OnRedirectToLogin = cxt =>
                    {
                        cxt.Response.StatusCode = 401;
                        return Task.CompletedTask;
                    },
                    OnRedirectToAccessDenied = cxt =>
                    {
                        cxt.Response.StatusCode = 403;
                        return Task.CompletedTask;
                    },
                    OnRedirectToLogout = cxt => Task.CompletedTask
                };
            });
    }

...并且Identity在这里与EF配置结合在一起...

       public static IServiceCollection ConfigureEntityFramework(this IServiceCollection services, string connectionString)
    {
        services
            .AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(connectionString))
            .AddIdentity<ApplicationUser, IdentityRole>(options =>
                {

                    // Password settings
                    options.Password.RequireDigit = true;
                    options.Password.RequiredLength = 8;
                    options.Password.RequireNonAlphanumeric = true;

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

                    // User settings
                    options.User.RequireUniqueEmail = true;
                })
            .AddRoleManager<RoleManager<IdentityRole>>()
            .AddSignInManager<SignInManager<ApplicationUser>>()
            .AddEntityFrameworkStores<ApplicationDbContext>()
            .AddDefaultTokenProviders();

        return services;
    }

我的vue.config.js看起来像这样...

const baseUrl = ''

module.exports = {
    publicPath: baseUrl + '/',

    // place our built files into the parent project where they will be copied
    // into the distribution for deployment
    outputDir: '../wwwroot',

    filenameHashing: true, //process.env.NODE_ENV === 'production',
    lintOnSave: 'error',

    css: {
        modules: false,
        sourceMap: process.env.NODE_ENV !== 'production',
        loaderOptions: {
            sass: {
                data: `
                    $fa-font-path: ${process.env.NODE_ENV !== 'production' ? '"~/fonts"' : '"' + baseUrl + '/fonts"'};
                    @import "@/scss/base/index.scss";
                    @import "@/scss/helpers/index.scss";
                `
            }
        }
    },

    devServer: {
        host: 'localhost',
        port: 8080,
        hot: true,
        open: true,
        openPage: '',
        overlay: true,
        disableHostCheck: true,
        proxy: {
            // Proxy services to a backend API
            '/api': {
                target: process.env.PROXY || 'https://localhost:44368',
                secure: false,
                changeOrigin: true
            }
        }
    },

    // these node_modules use es6 so need transpiling for IE
    transpileDependencies: [
    ]
}

1 个答案:

答案 0 :(得分:0)

我最终通过配置应用程序解决了该问题,以便仅在未处于开发模式时才强制使用HTTPS。 HTTPS杀死了底层的Webpack开发服务器,因此替换了热模块-我现在可以在主窗口中成功调试了!

很高兴能获得比该解决方案更好的解决方案,尽管它可以在不终止SSL的情况下(如果可能)运行。