I build an app that used JWT for authentication, I need to add windows authentication as other method, to switch between both, as customer need.
I have created a middleware to do this job, It worked probably while development. though, when I publish the release & deploy it in IIS I got error this
The Negotiate Authentication handler cannot be used on a server that directly supports Windows Authentication. Enable Windows Authentication for the server and the Negotiate Authentication handler will defer to it.
this is JWT Authentication code. Note: every thing configured to work in JWT Auth.
// Dependency Injection.cs
string? authScheme = configuration["AuthenticationScheme"];
if (authScheme) {
JwtTokenConfig? jwtTokenConfig = configuration.GetSection("jwtTokenConfig").Get<JwtTokenConfig>();
services.AddSingleton(jwtTokenConfig);
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(x =>
{
// options
}).AddNegotiate();
// JWT Authentication (Anonymous)
services.AddScoped<IAuthManager, JwtAuthManager>();
services.AddHostedService(sp => new JwtRefreshTokenCache(new JwtAuthManager(jwtTokenConfig)));
// Add CORS services
services.AddCors(options =>
{options.AddPolicy("AllowSpecificOrigin",
builder => builder.WithOrigins("http://localhost:4200")
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials());
});
}
}
this is the middleware code
public class AuthMiddleware
{
private readonly RequestDelegate _next;
private readonly IConfiguration _configuration;
public AuthMiddleware(RequestDelegate next, IConfiguration configuration)
{
_next = next;
_configuration = configuration;
}
public async Task InvokeAsync(HttpContext context)
{
var authScheme = _configuration["AuthenticationScheme"];
var publicRoutes = new List<string>
{ "/",
"/api/v1",
"/api/v1/Account/Login" };
if (publicRoutes.Any(route => context.Request.Path.StartsWithSegments(route, StringComparison.OrdinalIgnoreCase)))
{ await _next(context); return; }
AuthenticateResult result = null;
if (authScheme == "Windows") { result = await context.AuthenticateAsync(NegotiateDefaults.AuthenticationScheme); }
else if (authScheme == "JwtBearer")
{ result = await context.AuthenticateAsync(JwtBearerDefaults.AuthenticationScheme); }
if (result != null && result.Succeeded)
{ context.User = result.Principal; await _next(context); }
else { await context.ChallengeAsync(); }
}
}
Base Controller to inherit the Auth method to rest of controllers.
// [Authorize(AuthenticationSchemes = IISDefaults.AuthenticationScheme)]
[Authorize]
public class BaseController<T> : Controller
Program.cs
app.UseAuthentication();
app.UseMiddleware<AuthMiddleware>();
app.UseAuthorization();
I’ve tried changing the IIS settings, Application Pool Identity, changing windows authentication providers.
I tried to implement it without Negotiate.
if I turn Windows Authentication off in IIS, the web will stop completely with 404 error, if I turned windows authentication on, it ask me to login through it, and even if I did nothing happened.
the app is completely off, no page is shown even login page, because the error in program.cs so nothing will work at all.