Как настроить сайт dotnetcore 3 для возврата 401 с настраиваемым фильтром авторизации вместо перенаправления на страницу AccessDenied - PullRequest
1 голос
/ 08 января 2020

У меня есть сайт, использующий новый шаблон dotnetcore3 angular. Я создал собственный фильтр авторизации, который в настоящее время очень прост

public class ClaimRequirementFilter : IAuthorizationFilter
{
    readonly string _claim;

    public ClaimRequirementFilter(string claim)
    {
        _claim = claim;
    }

    public void OnAuthorization(AuthorizationFilterContext context)
    {

        if (_claim != "test")
        {
            context.Result = new ForbidResult();
        }
    }
}
public class ClaimRequirementAttribute : TypeFilterAttribute
{
    public ClaimRequirementAttribute(string claimType) : base(typeof(ClaimRequirementFilter))
    {
        Arguments = new object[] {claimType };
    }
}
    [Route("{jobId}")]
    [ClaimRequirement("testfail")]
    [HttpGet]
    public async Task<IActionResult> GetJob([FromRoute] Guid jobId)
    {
      //stuff
    {

Однако, когда запрос не выполняется (и это будет все из них сейчас), я получаю AccessDenied страница с returnUrl URL, который я пытался нажать.

Однако, поскольку этот запрос выполняется от моего angular клиента, я бы предпочел, чтобы он просто возвращал 401 (или 403), поскольку в этом случае пользователь, вошедший в систему, не имеет разрешения делать то, что он пытаюсь сделать), и я не уверен, как его настроить.

По запросу Ruard, вот моя конфигурация запуска

public class Startup
    {
        public Startup(IWebHostEnvironment env, IConfiguration configuration)
        {
            var builder = new ConfigurationBuilder()
                .SetBasePath(env.ContentRootPath)
                .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
                .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
                .AddEnvironmentVariables();
            Configuration = builder.Build();
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddApplicationInsightsTelemetry();
            services.AddDbContext<ApplicationDbContext>(
              options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))
            );

            services.AddTransient<EmailSender, EmailSender>();
            services.AddScoped<IRazorViewToStringRenderer, RazorViewToStringRenderer>();
            services.Configure<EmailServiceConfiguration>(Configuration.GetSection("EmailServiceConfiguration"));
            services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

            services.AddIdentity<ApplicationUser, IdentityRole>()
                    .AddDefaultTokenProviders()
                    .AddEntityFrameworkStores<ApplicationDbContext>();

            services.AddIdentityServer(options =>
                    {
                        options.UserInteraction.LoginUrl = "/auth/login";
                        options.UserInteraction.LogoutUrl = "/auth/logout";
                    })
                    //.AddDeveloperSigningCredential()
                    .AddApiAuthorization<ApplicationUser, ApplicationDbContext>();


            services.AddAuthentication()
                    // .AddGoogle(options =>
                    //   {
                    //     IConfigurationSection googleAuthNSection = Configuration.GetSection("Authentication:Google");
                    //     options.ClientId = googleAuthNSection["ClientId"];
                    //     options.ClientSecret = googleAuthNSection["ClientSecret"];
                    //   })
                    .AddIdentityServerJwt();


            services.AddControllersWithViews().AddRazorRuntimeCompilation();

            services.AddRazorPages(options =>
            {
                options.Conventions.AddAreaPageRoute("Identity", "/Identity/Account/Login", "/auth/login");
            });


            services.AddAuthorization(options =>
            {
                // options.AddPolicy("RequireAdmin", policy =>
                // {
                //   policy.RequireRole("Admin");
                // });

                // options.AddPolicy("CreateInternalUsers", policy =>
                // {
                //   // policy.RequireRole("Admin");
                //   policy.RequireClaim("CreatePPGUser");
                // });
            });

            // In production, the Angular files will be served from this directory
            services.AddSpaStaticFiles(configuration =>
            {
                configuration.RootPath = "ClientApp/dist";
            });
            services.AddControllers()
              .AddNewtonsoftJson(options =>
              {
                  options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
              });
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ApplicationDbContext context, IServiceProvider services)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseDatabaseErrorPage();
            }
            else
            {
                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();
            }
            context.Database.Migrate();
            app.UseHttpsRedirection();
            app.UseStaticFiles();
            if (!env.IsDevelopment())
            {
                app.UseSpaStaticFiles();
            }

            app.UseRouting();

            app.UseAuthentication();
            app.UseIdentityServer();
            app.UseAuthorization();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller}/{action=Index}/{id?}"
                  );

                endpoints.MapRazorPages();
            });

            app.UseSpa(spa =>
            {
                // To learn more about options for serving an Angular SPA from ASP.NET Core,
                // see https://go.microsoft.com/fwlink/?linkid=864501

                spa.Options.SourcePath = "ClientApp";

                if (env.IsDevelopment())
                {
                    // spa.UseAngularCliServer(npmScript: "start");
                    spa.UseProxyToSpaDevelopmentServer("http://localhost:4200");
                }
            });

            CreateUserRoles(services).Wait();
        }
}

1 Ответ

0 голосов
/ 09 января 2020

Вы должны добавить контроллер, который служит в качестве API. Из документации :

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase

Методы этого контроллера будут возвращать StatusCode вместо перенаправления пользователя на представление.


Update

В зависимости от вашего запуска кажется, что вы не устанавливаете CompatibilityVersion:

services.AddMvc()
        .SetCompatibilityVersion(CompatibilityVersion.Version_3_0);

Как указано в документации , это необходимо в сочетании с ApiController:

Предыдущее изменение:

  • Требуется использовать атрибут [ApiController] на уровне контроллера.
  • Включает потенциально нарушающее поведение, введенное в ASP. NET Core 2.2.

В вашем случае предполагается версия 3.0:

services.AddControllers()
    .AddNewtonsoftJson(options =>
    {
        options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
    })
    .SetCompatibilityVersion(CompatibilityVersion.Version_3_0);
...