im building some blazor wasm app i have to use windows autch because it is for corporate users only. so i have
builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme).AddNegotiate();
and i have some user controller that take care of getting username. now i want to protect whole api so user canot use my api (because they are domain authenticated) ,only this WASM shoult be able to use this api and swagger in development.
what is best practise for this ? jwt also ? just for api protection and not pure user authentication ?
i did generated some jwt
[HttpGet]
[Authorize]
[Route("GetUser")]
public UserModel GetUser()
{
string? login = httpContextAccessor!.HttpContext!.User?.Identity?.Name?.Replace("domain\\", "");
return new UserModel{ UserName=login , JWT = CreateJWT(login)};
}
private string? CreateJWT(string? userName)
{
if (userName == null) return null;
var secretkey = new SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes(this.appSettings.JWTSettings!.Secret!));
var credentials = new SigningCredentials(secretkey, SecurityAlgorithms.HmacSha256);
var claims = new[]
{
new Claim(ClaimTypes.Name, userName),
new Claim(JwtRegisteredClaimNames.Sub, userName)
};
var token = new JwtSecurityToken(issuer: "xxx", audience: "xxx", claims: claims, expires: DateTime.Now.AddMinutes(int.Parse(this.appSettings.JWTSettings.ExpireTime!)), signingCredentials: credentials);
return new JwtSecurityTokenHandler().WriteToken(token);
}
}
but how to force api to check this jwt also ? i tryied
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = true,
ValidAudience = "xxx",
ValidateIssuer = true,
ValidIssuer = "xxx",
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes(a.JWTSettings.Secret!))
};
});
but this did not changed anything. can the app have two times builder.Services.AddAuthentication
?
if no then i need to build some custom middleware ? or is there some better soliution ?
thanks and regards
CodePudding user response:
ok so for future searchers. for this to work this way i wanted we need :
builder.Services.AddAuthentication((options) =>
{
options.DefaultAuthenticateScheme = "JwtBearer";
options.DefaultChallengeScheme = "JwtBearer";
}).AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = true,
ValidateIssuer = true,
ValidIssuer = builder.Configuration["JWT:Issuer"],
ValidAudience = builder.Configuration["JWT:Issuer"],
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new
SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes(builder.Configuration["JWT:Key"]))
};
}).AddNegotiate();
then i added
builder.Services.AddAuthorization(options =>
{
var defaultAuthorizationPolicyBuilder = new AuthorizationPolicyBuilder(JwtBearerDefaults.AuthenticationScheme);
defaultAuthorizationPolicyBuilder = defaultAuthorizationPolicyBuilder.RequireAuthenticatedUser();
options.DefaultPolicy = defaultAuthorizationPolicyBuilder.Build();
});
and
app.MapControllers().RequireAuthorization();
this add automaticly invisible
[Authorize(AuthenticationSchemes=JwtBearerDefaults.AuthenticationScheme)]
to all my controllers
and finaly for just getUser method where this jwt is generated and windows username is grabbed need
[Authorize(AuthenticationSchemes = NegotiateDefaults.AuthenticationScheme)]