Blazor WASM on Windows 2016 Server Hosted with IIS, Authentication Token failed

DerDerErIst 1 Reputation point
2021-06-11T16:57:05.36+00:00

Hello, I'm relatively new to Blazor

Here is a whole Blog Post about it and my Server Settings and everything:
https://stusse.de/setup-windows-server-2016-with-blazor-webassembly-app-authentication-failed-part-1/

Short Info:

I Wanna create a Blazor WASM for my Business. So it handles Highscorelists for my Developed Games as well as storing User Data and Game Informations, which also should be managed and accessed online through a Web interface.

What Is the Problem?

I'm Running the standard Blazor WASM Core hosted with Integrated User Accounts Template on my Windows 2016 Server with IIS Here is a link to the Live Site - Stusse Server. But for some reason, I don't understand, the Login, as well as Redirection, seems not to work properly and the Client Side of the Blazor WASM loses the Connect Token.

Testing:

I have tested the same Blazor WASM Template running locally on my Personal Computer as well as on the Server running locally without any issues. It's only once I Publish the Blazor WASM to my IIS Server.

The only changes I've made to the Blazor WASM Template are here in my AppSettings.json, to implement a Key and the Certificate and also the correct Connection String which works, how I said, locally just fine but not in the Live Environment.

{ "ConnectionStrings": { "DefaultConnection": "Server=XXX;Database=XXX;User ID = XXX; Password = XXX;MultipleActiveResultSets=true" }, "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } }, "IdentityServer": { "Clients": { "StusseServer.Client": { "Profile": "IdentityServerSPA" } }, "Key": { "Type": "Store", "StoreName": "My", "StoreLocation": "LocalMachine", "Name": "CN=XXX" } }, "AllowedHosts": "*" }

Now my Questions:

Are there Roles or Features from the Windows Server I might need to add for the Live Environment?
Or any IIS Modul I need? Some other Server Configurations I have to make?
Or do I miss some Settings in the App so the App can work in a Live Environment?

The Windows Server is a kinda Fresh Installation, with Standart Web Server Configurations, IIS Server, and .Net Frameworks
It contains a MSSQL with MSSMS, Visual Studio, Core SDK, Net SDK, Core Hosting Bundle

I hope someone can help me figure this out. I'm testing and searching already long, to fix that problem but I don't find an answer to my problem. If you need additional pieces of information feel free to ask.

Edit:
Some Additions When you are Logged in and Try to Access Pages on the App:
![104809-grafik.png][1]
[1]: /api/attachments/104809-grafik.png?platform=QnA

If you Click on Register once you logged in you get routed to the Register Page and you can Access the Profile
![104790-grafik.png][1]
[1]: /api/attachments/104790-grafik.png?platform=QnA

But on Client-Side the Token seems not to be available anymore
![104840-grafik.png][1]
[1]: /api/attachments/104840-grafik.png?platform=QnA

Adding Code:
launchSettings.Json

{  
  "iisSettings": {  
    "windowsAuthentication": false,  
    "anonymousAuthentication": true,  
    "iis": {  
      "applicationUrl": "https://www.stusse-server.com:14424",  
      "sslPort": 44320  
    }  
  }  
}  

AppSettings.Json

{  
  "ConnectionStrings": {  
    "DefaultConnection": "Server=xxx;Database=xxx;User ID = xxx; Password = xxx;MultipleActiveResultSets=true"  
  },  
  "Logging": {  
    "LogLevel": {  
      "Default": "Information",  
      "Microsoft": "Warning",  
      "Microsoft.Hosting.Lifetime": "Information"  
    }  
  },  
  "IdentityServer": {  
    "Authority": "https://www.stusse-server.com",  
    "ResponseType": "authorization_code",  
    "DefaultScopes": [  
      "openid",  
      "profile"  
    ],  
    "PostLogoutRedirectUri": "https://www.stusse-server.com/authentication/logout-callback",  
    "RedirectUri": "https://www.stusse-server.com/authentication/login-callback",  
    "Clients": {  
      "StusseServer.Client": {  
        "Profile": "IdentityServerSPA"  
      }  
    },  
    "Key": {  
      "Type": "Store",  
      "StoreName": "My",  
      "StoreLocation": "LocalMachine",  
      "Name": "CN=stusse-server.com"  
    }  
  },  
  "Authentication": {  
    "Google": {  
      "ClientId": "xxx.apps.googleusercontent.com",  
      "ClientSecret": "xxx",  
      "ResponseType": "authorization_code"  
    }  
  },  
  "AllowedHosts": "*"  
}  

Client - Program.cs

public class Program  
    {  
        public static async Task Main(string[] args)  
        {  
            var builder = WebAssemblyHostBuilder.CreateDefault(args);  
            builder.RootComponents.Add<App>("app");  
  
            builder.Services.AddHttpClient("StusseServer.ServerAPI", client => client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress))  
                        .AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();  
  
            // Supply HttpClient instances that include access tokens when making requests to the server project  
            builder.Services.AddScoped(sp => sp.GetRequiredService<IHttpClientFactory>().CreateClient("StusseServer.ServerAPI"));  
  
            builder.Services.AddApiAuthorization()  
                .AddAccountClaimsPrincipalFactory<CustomUserFactory>();  
  
            builder.Services.AddOidcAuthentication(options =>  
            {  
                builder.Configuration.Bind("IdentityServer", options.ProviderOptions);  
            });  
  
            await builder.Build().RunAsync();  
        }  
    }  

And the Startup.cs

public class Startup  
    {  
        public Startup(IConfiguration configuration)  
        {  
            Configuration = configuration;  
        }  
  
        public IConfiguration Configuration { get; }  
  
        // This method gets called by the runtime. Use this method to add services to the container.  
        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940  
        public void ConfigureServices(IServiceCollection services)  
        {  
            services.AddDbContext<ApplicationDbContext>(options =>  
                options.UseSqlServer(  
                    Configuration.GetConnectionString("DefaultConnection")));  
  
            services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = false)  
                .AddRoles<IdentityRole>()  
                .AddEntityFrameworkStores<ApplicationDbContext>();  
  
            services.AddIdentityServer()  
                .AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options =>  
                {  
                    options.IdentityResources["openid"].UserClaims.Add("name");  
                    options.ApiResources.Single().UserClaims.Add("name");  
                    options.IdentityResources["openid"].UserClaims.Add("role");  
                    options.ApiResources.Single().UserClaims.Add("role");  
                });  
  
            services.AddTransient<IProfileService, ProfileService>();  
  
            JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("role");  
  
            services.AddCors(options =>  
            {  
                options.AddDefaultPolicy(builder =>  
                    // TODO: this should be limited only to specified sources  
                    builder.WithOrigins("https://www.stusse-server.com:44320")  
                            .AllowAnyMethod()  
                            .AllowAnyHeader()  
                            .AllowCredentials());  
            });  
  
            services.AddAuthentication()                  
            .AddIdentityServerJwt()              
                .AddGoogle(google =>  
                {  
                    google.ClientId = Configuration["Authentication:Google:ClientId"];  
                    google.ClientSecret = Configuration["Authentication:Google:ClientSecret"];  
                });  
            //.AddIdentityServerJwt();  
            //services.AddAuthentication().AddGoogle(googleOptions =>  
            //    {  
            //        googleOptions.ClientId = Configuration["Authentication:Google:ClientId"];  
            //        googleOptions.ClientSecret = Configuration["Authentication:Google:ClientSecret"];  
            //    });  
  
            services.Configure<IdentityOptions>(options =>  
            {  
                // Default Password settings.  
                options.Password.RequireDigit = false;  
                options.Password.RequireLowercase = false;  
                options.Password.RequireNonAlphanumeric = false;  
                options.Password.RequireUppercase = false;  
                options.Password.RequiredLength = 4;  
                options.Password.RequiredUniqueChars = 1;  
            });  
  
            services.Configure<ForwardedHeadersOptions>(options =>  
            {  
                options.ForwardedHeaders =  
                    ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;  
            });  
  
  
            services.ConfigureApplicationCookie(options =>  
            {  
                options.AccessDeniedPath = "/Identity/Account/AccessDenied";  
                options.Cookie.Name = "StusseServerAccountCookie";  
                options.ExpireTimeSpan = TimeSpan.FromMinutes(60);  
                options.LoginPath = "/Identity/Account/Login";  
                options.ReturnUrlParameter = CookieAuthenticationDefaults.ReturnUrlParameter;  
                options.SlidingExpiration = true;  
            });  
  
            services.AddControllersWithViews();  
            services.AddRazorPages();  
        }  
  
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.  
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)  
        {  
            app.UseForwardedHeaders();  
  
            if (env.IsDevelopment())  
            {  
                app.UseDeveloperExceptionPage();  
                app.UseDatabaseErrorPage();  
                app.UseWebAssemblyDebugging();  
            }  
            else  
            {  
                app.UseExceptionHandler("/Error");  
                app.UseHsts();  
            }  
  
            app.UseHttpsRedirection();  
            app.UseBlazorFrameworkFiles();  
            app.UseStaticFiles();  
  
            app.UseRouting();  
  
            app.UseIdentityServer();  
            app.UseAuthentication();  
            app.UseAuthorization();  
            app.UseCookiePolicy();  
  
            app.UseCors();  
  
            app.UseEndpoints(endpoints =>  
            {  
                endpoints.MapRazorPages();  
                endpoints.MapControllers();  
                endpoints.MapFallbackToFile("index.html");  
            });  
        }  
    }  
Entity Framework Core
Entity Framework Core
A lightweight, extensible, open-source, and cross-platform version of the Entity Framework data access technology.
697 questions
Internet Information Services
ASP.NET Core
ASP.NET Core
A set of technologies in the .NET Framework for building web applications and XML web services.
4,165 questions
Blazor
Blazor
A free and open-source web framework that enables developers to create web apps using C# and HTML being developed by Microsoft.
1,390 questions
{count} votes