0
votes

Im using the default asp.net core + angular scaffold with identity to host my SPA inside of a MVC application, the authentication part works as it should inside of the angular SPA.

My startup.cs is nothing special, standard .net core scaffold stuff:

public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<ApplicationDbContext>(options =>
                options.UseSqlServer(
                    Configuration.GetConnectionString("DbName")));

            services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
                .AddEntityFrameworkStores<ApplicationDbContext>();

            services.AddIdentityServer()
                .AddApiAuthorization<ApplicationUser, ApplicationDbContext>();

            services.AddAuthentication()
                .AddIdentityServerJwt();
            services.AddControllersWithViews().AddRazorRuntimeCompilation();
            services.AddRazorPages();
            services.AddHttpContextAccessor();
            // In production, the Angular files will be served from this directory
            services.AddSpaStaticFiles(configuration =>
            {
                configuration.RootPath = "ClientApp/dist";
            });
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {

            if (env.IsDevelopment())
            {
                app.UseBrowserLink();
                app.UseDeveloperExceptionPage();
                app.UseDatabaseErrorPage();
            }
            else
            {
                app.UseExceptionHandler("/Error");
                app.UseHsts();
            }

            app.UseHttpsRedirection();
            app.UseStaticFiles();
            if (!env.IsDevelopment())
            {
                app.UseSpaStaticFiles();
            }

            app.UseRouting();

            app.UseAuthentication();
            app.UseIdentityServer();
            app.UseAuthorization();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller}/{action=Index}/{id?}");
                endpoints.MapRazorPages();
            });

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

                if (env.IsDevelopment())
                {
                    spa.UseProxyToSpaDevelopmentServer("http://localhost:4200");
                }
            });
        }
    }

I also serve razor views via .net core controllers for a different part of the application, however the scaffollded authentication does not work here at all.

Here is what happens currently:

  1. Go to adress, protected angular router guard redirect me to scaffolded login page.
  2. I login and get redirected to the SPA.'

When I "path traverse" out of the SPA the problem occurs:

  1. I go to: http://myadress/mycontroller/MyAction) I get logged out of the application and using a simple controller with a UserManager<ApplicationUser> I check if the HttpContext.User exists:
        public IActionResult MyAction()
        {
            //user cannot be found here.
            var user = _userManager.GetUserAsync(HttpContext.User);
            
            return View();
        }

I tried putting a [Authorize] thinking a redirect to the login page again should help me get logged into the "Mvc part" of the app. (since earlier I logged in with a redirectURL to the SPA), but no succes: I get a 401 upon visiting without any more information.

The desired outcome I have with this whole debacle is as follows:

  • 2 parts of an application hosted in asp.net core; 1 is your standard MVC app with razor views (admin only) and the other a SPA in angular for clients (client only).
  • once A user logs in, he/she gets redirected based on role the right part of the app, so /dashboard for admins (MVC) and /app for clients (angular)

This is basically it, I dont think this should be that difficult but im pretty new to asp.net core.

I hope I have given enough information, any help is appreciated.

1

1 Answers

0
votes

You will need to share the same stateless authorisation cookie between MVC, web API and the SPA.

I suggest using a .NET HttpOnly cookie.

When the SPA initially loads, you can query the Web API for the user permissions. If the cookie exists it will be sent through with the request and you can return the user permissions, otherwise return nothing - which indicates the user is not logged in.

I have successfully done this using a React SPA + Core Web API for admin and Core MVC for a Server Side Rendered front-end.