У меня есть такая конфигурация авторизации. Проблема в том, что я хочу проверить субмодуль и есть ли у него права. У меня также есть контроллер входа в систему, где я создаю заявки и т. Д. И добавляю их. Но я думаю, что я что-то здесь тоже упускаю. Я должен добавить претензии к текущему участнику, я думаю, но я не знаю, как:
Вот мое действие входа в систему в контроллере входа
[HttpGet("login")]
public IActionResult Login()
{
var userName = _httpContextAccessor.HttpContext.User.Identity.Name.GetUserNameFromHttpContext();
var user = _userClient.GetUserByUserName(userName);
var loggedIUserDto = new LoggedInUserDto {UserName = userName};
var claims = new List<Claim>();
if (user == null)
{
return Unauthorized($"User {userName} does not exits in DB");
}
var userModulesWithSubmodules = _loginClient.GetUserModulesWithSubmodules(userName);
loggedIUserDto.UserModulesWithSubmodules = userModulesWithSubmodules;
if (userModulesWithSubmodules.Count == 0)
{
return Conflict($"User {userName} has no modules");
}
foreach (var module in userModulesWithSubmodules)
{
foreach (var submodule in module.Submodules)
{
var submoduleActionList = new List<string>();
if (submodule.CanAdd)
{
submoduleActionList.Add("CanAdd");
}
if (submodule.CanEdit)
{
submoduleActionList.Add("CanEdit");
}
if (submodule.CanRead)
{
submoduleActionList.Add("CanRead");
}
if (submodule.CanDelete)
{
submoduleActionList.Add("CanDelete");
}
claims.Add(new Claim(ClaimTypes.Name, user.UserName));
claims.Add(new Claim(submodule.SubmoduleName, string.Join(',', submoduleActionList)));
}
}
var claimsIdentity = new ClaimsIdentity(claims);
var claimsPrincipal = new ClaimsPrincipal(claimsIdentity);
Thread.CurrentPrincipal = claimsPrincipal;
return Ok(loggedIUserDto);
}
CustomeAuthorize
public class CustomAuthorize : AuthorizeAttribute
{
private SubmoduleActionType _submoduleActionType;
private SubmoduleType _submoduleType;
public SubmoduleActionType ActionType;
public SubmoduleType Type {
get => _submoduleType;
set
{
_submoduleType = value;
Policy = $"{_submoduleType.ToString()};{_submoduleActionType.ToString()}";
}
}
public CustomAuthorize(SubmoduleActionType submoduleActionType, SubmoduleType submoduleType)
{
_submoduleActionType = submoduleActionType;
_submoduleType = submoduleType;
}
}
Ниже приведен мой класс требований:
public class SubmoduleTypeRequirement : IAuthorizationRequirement
{
public SubmoduleActionType? ActionType { get; set; }
public SubmoduleType? Type { get; set; }
public SubmoduleTypeRequirement(SubmoduleActionType actionType, SubmoduleType type)
{
Type = type;
ActionType = actionType;
}
}
Вот мой класс Handler
public class SubmoduleAuthorizationHandler : AuthorizationHandler<SubmoduleTypeRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, SubmoduleTypeRequirement submoduleRequirement)
{
if (!submoduleRequirement.ActionType.HasValue)
{
throw new ArgumentException("No action type provided");
}
if (!submoduleRequirement.Type.HasValue)
{
throw new ArgumentException("No submodule type provided");
}
if (!context.User.HasClaim(uc => uc.Type == submoduleRequirement.Type.ToString()))
{
context.Fail();
return Task.FromResult(0);
}
var grantedRights = Convert.ToString(context.User.FindFirst(c => c.Type == submoduleRequirement.Type.ToString()));
if (grantedRights.Contains(submoduleRequirement.ActionType.ToString()))
{
context.Succeed(submoduleRequirement);
}
return Task.FromResult(0);
}
}
И, наконец, класс политики:
public class SubmodulePolicy : IAuthorizationPolicyProvider
{
public SubmodulePolicy(IOptions<AuthorizationOptions> options)
{
DefaultPolicyProvider = new DefaultAuthorizationPolicyProvider(options);
}
public DefaultAuthorizationPolicyProvider DefaultPolicyProvider { get; }
public Task<AuthorizationPolicy> GetPolicyAsync(string policyName)
{
var submoduleTypeAndAction = policyName.Split(";");
var submoduleTypeString = submoduleTypeAndAction[0];
var actionTypeString = submoduleTypeAndAction[1];
var submoduleTypeParsed = System.Enum.TryParse(submoduleTypeString, out SubmoduleType submoduleType);
var actionTypeParsed = System.Enum.TryParse(actionTypeString, out SubmoduleActionType submoduleActionType);
if (actionTypeParsed && submoduleTypeParsed)
{
var policy = new AuthorizationPolicyBuilder();
policy.AddRequirements(new SubmoduleTypeRequirement(submoduleActionType, submoduleType));
return Task.FromResult(policy.Build());
}
if (!actionTypeParsed || !submoduleTypeParsed)
{
throw new ArgumentException("Cannot parse action or submoduleType from Policy");
}
return DefaultPolicyProvider.GetPolicyAsync(policyName);
}
public Task<AuthorizationPolicy> GetDefaultPolicyAsync()
{
return DefaultPolicyProvider.GetDefaultPolicyAsync();
}
}
Проблема в том, что мой код никогда не будет доступен для моего GetPolicy. Это всегда идет к методу GetDefaultPolicyAsync. Даже атрибут не уволен. Должен ли я где-нибудь изменить пользовательский атрибут? Я сомневаюсь, что. Все, что я нахожу в Интернете, даже в официальных документах, всегда с одним аргументом, но мне нужно два из них.
Да, и вот моя конфигурация в классе запуска
services.AddTransient<IAuthorizationPolicyProvider, SubmodulePolicy>();
services.AddSingleton<IAuthorizationHandler, SubmoduleAuthorizationHandler>();
services.AddAuthorization();
Есть идеи, что случилось? Есть ли ограничение только для одного аргумента? Также я думаю о замене этого фильтра.
РЕДАКТИРОВАТЬ:
Как и просил мой класс запуска. Просто чтобы прокомментировать - конфигурация jwt отключена, так как у меня была проблема с получением файла json с константами (мне было предложено ввести имя пользователя и пароль при получении файла - сервер iis). Этот веб-интерфейс в сочетании с угловой 2+ (v7)
Мой класс запуска:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public IContainer ApplicationContainer { get; private set; }
// This method gets called by the runtime. Use this method to add services to the container.
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(IISDefaults.AuthenticationScheme);
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
.AddJsonOptions(options => options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver());
services.AddTransient<IAuthorizationPolicyProvider, SubmodulePolicy>();
services.AddSingleton<IAuthorizationHandler, SubmoduleAuthorizationHandler>();
//var appSettingsSection = Configuration.GetSection("Settings");
//services.Configure<AppSettings>(appSettingsSection);
//var appSettings = appSettingsSection.Get<AppSettings>();
//var key = Encoding.ASCII.GetBytes(appSettings.Secret);
//services
// .AddAuthentication(auth =>
// {
// auth.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
// auth.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
// })
// .AddJwtBearer(jwtBearer =>
// {
// jwtBearer.RequireHttpsMetadata = false;
// jwtBearer.SaveToken = true;
// jwtBearer.TokenValidationParameters = new TokenValidationParameters
// {
// ValidateIssuerSigningKey = true,
// IssuerSigningKey = new SymmetricSecurityKey(key),
// ValidateIssuer = false,
// ValidateAudience = false
// };
// });
services.AddAuthorization();
services.Configure<IISServerOptions>(options =>
{
options.AutomaticAuthentication = true;
});
services.AddHttpContextAccessor();
var container = new ContainerBuilder();
container.RegisterType<PermissionsClient>()
.As<IPermissionsClient>()
.WithParameter("baseServiceUrl", Configuration.GetSection("Settings")["BaseApiUrl"])
.WithParameter("clientCertThumbprint", Configuration.GetSection("Settings")["BaseApiClientThumbPrint"])
.SingleInstance();
container.RegisterType<LoginClient>()
.As<ILoginClient>()
.WithParameter("baseServiceUrl", Configuration.GetSection("Settings")["BaseApiUrl"])
.WithParameter("clientCertThumbprint", Configuration.GetSection("Settings")["BaseApiClientThumbPrint"])
.SingleInstance();
container.RegisterType<UserClient>()
.As<IUserClient>()
.WithParameter("baseServiceUrl", Configuration.GetSection("Settings")["BaseApiUrl"])
.WithParameter("clientCertThumbprint", Configuration.GetSection("Settings")["BaseApiClientThumbPrint"])
.SingleInstance();
container.RegisterType<SenderClient>()
.As<ISenderClient>()
.WithParameter("baseServiceUrl", Configuration.GetSection("Settings")["BaseApiUrl"])
.WithParameter("clientCertThumbprint", Configuration.GetSection("Settings")["BaseApiClientThumbPrint"])
.SingleInstance();
container.Populate(services);
ApplicationContainer = container.Build();
return new AutofacServiceProvider(ApplicationContainer);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseAuthentication();
app.UseMvc();
}
}