Краткая версия:
У меня есть основное приложение Razorpages ASP.net, выполняющее аутентификацию пользователей Windows через .addNegotiate()
. Затем роли назначаются на основе групп AD через преобразователь утверждений, давайте назовем одну из добавленных ролей «Администратор». На основе этих ролей настроена дополнительная политика SiteAuth.
Авторизация в соответствии с политикой SiteAuth на бритвенной странице с использованием [Authorize(Policy = "SiteAuth")]
работает, однако [Authorize(Roles = "Admin")]
не работает и перенаправляется на неавторизованную страницу. Упрощение до [Authorize]
работает.
Дальше больше if (User.HasClaim(claim => claim.Value == "Admin"))
также работает как положено.
Я наблюдал, как преобразование утверждений происходит через точку останова при попадании на страницу, показывающую, что пользователь должен быть авторизован и утверждение добавлено.
Что я пропустил или сделал не так, что [Authorize(Roles = "Admin")]
не авторизуется должным образом?
Версия с более подробной технической информацией:
Program.cs – соответствующие части:
builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme)
.AddNegotiate();
builder.Services.AddAuthorization(options =>
{
// By default, all incoming requests will be authorized according to the default policy.
options.FallbackPolicy = options.DefaultPolicy;
options.AddPolicy("SiteAuth", policy => policy.RequireAssertion(
context => context.User.HasClaim(claim => claim.Type == ClaimTypes.Role && (new string[] { "SuperAdmin", "Admin", "User" }).Contains(claim.Value))));
});
builder.Services.AddControllers();
builder.Services.AddRazorPages().AddRazorPagesOptions(o =>
{
o.Conventions.ConfigureFilter(new IgnoreAntiforgeryTokenAttribute());
o.Conventions.Add(new ActionRouteConvention());
});
builder.Services.AddMemoryCache();
builder.Services.AddSession();
builder.Services.AddHttpContextAccessor();
builder.Services.AddScoped<IClaimsTransformation, ClaimsTransformer>();
/**** Other Services Added/Configured ***/
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
//app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseSession();
app.UseAuthentication();
app.UseStatusCodePagesWithReExecute("/errors/{0}");
app.UseAuthorization();
app.MapControllers();
app.MapRazorPages();
app.MapGet("/debug-claims", (ClaimsPrincipal user) =>
{
return Results.Ok(user.Claims.Select(c => new { c.Type, c.Value }));
}).RequireAuthorization();
app.Run();
ПретензииТрансформер
public class ClaimsTransformer : IClaimsTransformation
{
private readonly SiteSettings _siteSettings;
private readonly IHttpContextAccessor _context;
private readonly ILogger<ClaimsTransformer> _logger;
public ClaimsTransformer(IHttpContextAccessor httpContextAccessor, SiteSettings siteSettings, ILogger<ClaimsTransformer> logger)
{
_siteSettings= siteSettings;
_context= httpContextAccessor;
_logger = logger;
}
public Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
{
var wi = (WindowsIdentity)principal.Identity;
var ci = (ClaimsIdentity)principal.Identity;
var groups = wi.Groups;
if (groups != null)
{
foreach (var group in groups) //-- Getting all the AD groups that user belongs to---
{
try
{
string groupName = string.Empty;
if (_siteSettings.AdminGroups.TryGetValue(group.Translate(typeof(NTAccount)).ToString(), out groupName))
{
if (!principal.HasClaim(c => c.Value == groupName))
{
//var claim = new Claim("RAAuth", groupName);
//wi.AddClaim(claim);
_logger.LogInformation($"Adding role {groupName} to claims.");
var claim = new Claim(ClaimTypes.Role, groupName);
//wi.AddClaim(claim);
ci.AddClaim(claim);
//claim = new Claim(wi.RoleClaimType, group.Value);
//wi.AddClaim(claim);
}
}
}
catch (Exception ex)
{
throw ex;
}
}
}
return Task.FromResult(principal);
}
}
Информация об отладке
Сброс претензий на экран дает:
{
"type": "http://schemas.microsoft.com/ws/2008/06/identity/claims/role",
"value": "Admin"
},
{
"type": "http://schemas.microsoft.com/ws/2008/06/identity/claims/role",
"value": "SuperAdmin"
},
Это убедительно свидетельствует о том, что роли были применены.
Имя роли было скопировано и вставлено в [Authorize(Roles = "Admin")]
, чтобы исключить опечатки.
Надеюсь, я напутал здесь что-то простое.
Это связано с тем, что при использовании проверки подлинности Windows «Имя RoleClaim» отличается. Просто используйте следующее:
...
var ci = (ClaimsIdentity)principal.Identity;
...
var claim = new Claim(ci.RoleClaimType, groupName);
...
Тогда [Authorize(Roles = "Admin")]
сработает.
Чтобы уточнить:
ClaimTypes.Role: «http://schemas.microsoft.com/ws/2008/06/identity/claims/role»
ci.RoleClaimType: "http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid"
Можете ли вы использовать
AddTransient
для регистрации преобразователя претензий и проверить.