Условные атрибуты аутентификации .NET Core API для разработки и производства

Короче говоря, можно ли разместить атрибут авторизации на основе среды для моего API, чтобы ограничение полномочий было отключено в процессе разработки и снова включено в Production?

У меня есть отдельный проект Angular 2, который я хочу назвать .NET Core API. Мы создали отдельный проект, чтобы мы могли открыть проект Angular 2 в vscode и отладить typescript. По завершении мы построим проект и поместим его в проект .NET Core по соображениям безопасности.

Наша проблема заключается в том, что на этапах отладки мы не можем подключиться к API, потому что это два отдельных проекта, а наш проект Angular 2 не имеет Active Directory. Проект .NET Core в настоящее время имеет атрибуты аутентификации и не разрешает доступ (401) к API. Было бы неплохо, если бы мы могли отключить это во время разработки и вернуться во время производства.

Я также открыт для любых других предложений о том, как мы можем наилучшим образом решить эту проблему.

[Authorize: (Only in Production)] <-- // something like this???
[Route("api/[controller]")]
public class TestController : Controller
{
    ...

Ответ 1

Авторизация ASP.NET Core основана на политике. Как вы могли видеть, AuthorizeAttribute может принимать имя политики, чтобы он знал, какие критерии должны быть удовлетворены для того, чтобы запрос был разрешен. Я предлагаю вам прочитать отличную документацию по этому вопросу.

Возвращаясь к вашей проблеме, похоже, что вы не используете определенную политику, поэтому она использует значение по умолчанию, которое требует аутентификации пользователя по умолчанию.

Вы можете изменить это поведение в Startup.cs. Если вы находитесь в режиме разработки, вы можете переопределить политику по умолчанию, чтобы у нее не было никаких требований:

public void ConfigureServices(IServiceCollection services)
{
    services.AddAuthorization(x =>
    {
        // _env is of type IHostingEnvironment, which you can inject in
        // the ctor of Startup
        if (_env.IsDevelopment())
        {
            x.DefaultPolicy = new AuthorizationPolicyBuilder().Build();
        }
    });
}

Update

im1dermike упомянул в комментарии, что для AuthorizationPolicy требуется хотя бы одно требование, так как мы можем видеть здесь. Этот код не был введен недавно, так что это означает, что решение выше было сломано все время.

Чтобы обойти это, мы можем использовать RequireAssertion метод AuthorizationPolicyBuilder и добавить фиктивное требование. Это будет выглядеть так:

public void ConfigureServices(IServiceCollection services)
{
    services.AddAuthorization(x =>
    {
        // _env is of type IHostingEnvironment, which you can inject in
        // the ctor of Startup
        if (_env.IsDevelopment())
        {
            x.DefaultPolicy = new AuthorizationPolicyBuilder()
                .RequireAssertion(_ => true)
                .Build();
        }
    });
}

Это гарантирует, что у нас есть хотя бы одно требование в политике авторизации, и мы знаем, что он всегда будет проходить.

Ответ 2

Лично я бы установил среду моего dev как можно ближе к prd. В любое время, когда я начинаю делать что-то только в Dev, я ненавижу себя за это позже.

Используете ли вы проверку подлинности Windows? Когда Api запускается с использованием проверки подлинности Windows, он подберет пользователя идентификации пользователя api через приложение angular2. Поэтому для приложения angular2 не требуется Active Directory.

Но если вы хотите создать собственный атрибут AuthorizeAttribute, как было предложено. Вы можете сделать что-то вроде этого.

public class CustomAuthorize : AuthorizationFilterAttribute, IAuthorizationFilter
{

    public override void OnAuthorization(HttpActionContext actionContext)
    {
        bool devEnvironment = GetEnvironment();

        if (devEnvironment)
            return;
        else
            base.OnAuthorization(actionContext);


    }

    public override Task OnAuthorizationAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
    {
                    bool devEnvironment = GetEnvironment();

        if (devEnvironment)
            return;
        else
            base.OnAuthorization(actionContext);
    }

    private bool GetEnvironment(HttpActionContext actionContext, bool access)
    {
        // code that will tell you if you are in your dev environment or not
    }
}

Затем в вашем контроллере вы просто используете атрибут [CustomAuthorize].

Ответ 3

В итоге я могу помочь:

    public class OnlyDebugModeAttribute : ActionFilterAttribute
{
    public override void OnActionExecuted(ActionExecutedContext context)
    {
        base.OnActionExecuted(context);
    }

    public override void OnActionExecuting(ActionExecutingContext context)
    {
#if DEBUG

        //Ok
#else
        context.Result = new ForbidResult();
        return;
#endif

    }
}

а затем применить его на контроллере

[OnlyDebugMode]
[Route("api/[controller]")]
[ApiController]
public class DebugController : ControllerBase
{ 

Ответ 4

Вот мое решение:

Новый атрибут для ваших контроллеров:

[AzureADAuthorize]

AzureADAuthorize.cs:

public class AzureADAuthorize : AuthorizeAttribute
    {
        public AzureADAuthorize() : base(AzureADPolicies.Name)
        {
        }

    }

AzureADPolicies.cs:

public static class AzureADPolicies
    {
        public static string Name => "AzureADAuthorizationRequired";

        public static void Build(AuthorizationPolicyBuilder builder)
            {
                if (StaticRepo.Configuration.GetValue<bool>("EnableAuthorization") == true)
                {
                    var section = StaticRepo.Configuration.GetSection($"AzureAd:AuthorizedAdGroups");
                    var groups = section.Get<string[]>();
                    builder.RequireClaim("groups", groups);

                }
                else if (StaticRepo.Configuration.GetValue<bool>("EnableAuthentication") == true)
                {
                    builder.RequireAuthenticatedUser();
                }else
                {
                    builder
                    .RequireAssertion(_ => true)
                    .Build();
                }             
            }
    }

Startup.cs:

//Authentication & Authorization
            #region AUTHENTICATION / AUTHORICATION

            StaticRepo.Configuration = Configuration;


                services.AddAuthorization(options =>
                {
                    options.AddPolicy(
                        AzureADPolicies.Name, AzureADPolicies.Build);
                });

            services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
             .AddAzureAD(options => Configuration.Bind("AzureAd", options));

            #endregion

Appsettings.json:

 "EnableAuditLogging": false,
  "EnableAuthentication": true,
  "EnableAuthorization": false,
"AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "Domain": "https://MyDomain.onmicrosoft.com/",
    "TenantId": "b6909603-e5a8-497d-8fdb-7f10240fdd10",
    "ClientId": "6d09a1bf-4678-4aee-b67c-2d6df68d5324",
    "CallbackPath": "/signin-oidc",
    //Your Azure AD Security Group Object IDs that users needs to be member of to gain access
    "AuthorizedAdGroups": [
      "568bd325-283f-4909-9fcc-a493d19f98e8",
      "eee6d366-0f4d-4fca-9965-b2bc0770506d"
    ]
  }

(Это случайные направляющие)

Теперь вы можете использовать условный контроль, если хотите иметь анонимный доступ, аутентификацию Azure, аутентификацию + авторизацию группы. В файле манифеста приложения для рекламы Azure все еще есть некоторые вещи, которые вам нужно настроить, но я думаю, что это выходит за рамки этого.