Asp net core 403 error

I would like to return a 403 Forbidden to the client when trying to perform an invalid operation. What is the method I need to use? I searched over the internet but I found only these for MVC 5: ...

I would like to return a 403 Forbidden to the client when trying to perform an invalid operation. What is the method I need to use?

I searched over the internet but I found only these for MVC 5:

If the return type for your web api method is HttpResponseMessage then
you need to use the below code:

return Request.CreateErrorResponse(HttpStatusCode.Forbidden, "RFID is disabled for this site.");
Or  if the return type for your web api method is IHttpActionResult then you need to use the below code

return StatusCode(HttpStatusCode.Forbidden,"RFID is disabled for this site.");

How to return 403 for IActionResult type:

public IActionResult Put(string userid, [FromBody]Setting setting)
 {
    var result = _SettingsRepository.Update(userid, setting);
    if (result == true)
    {
       return Ok(201);
    }
    else
    {
       return BadRequest();
    }
 }

Camilo Terevinto's user avatar

asked Jul 14, 2017 at 6:10

wandermonk's user avatar

When you want to respond with a HTTP 403 status and allow ASP.NET Core’s authentication logic to handle the response with its forbidden handling logic (can be configured in your Startup class, and may cause a redirect to another page), use:

return Forbid();

(same applies to Unauthorized())


When you want to respond with a HTTP 403 status code from an API and do not want the ASP.NET Core authentication logic to perform any redirect or other action, use:

return StatusCode(403);

// or with developer-friendly type
return StatusCode(StatusCodes.Status403Forbidden);

// or as an api-friendly error response
return Problem(
    type: "/docs/errors/forbidden",
    title: "Authenticated user is not authorized.",
    detail: $"User '{user}' must have the Admin role.",
    statusCode: StatusCodes.Status403Forbidden,
    instance: HttpContext.Request.Path
);

The latter example produces a client error response.

answered Dec 8, 2017 at 6:26

Bart Verkoeijen's user avatar

Bart VerkoeijenBart Verkoeijen

15.8k7 gold badges53 silver badges56 bronze badges

4

Alternative to MstfAsan’s answer is to use:

return Forbid();

It is a method on the controller base class that does the same thing.

Or

return StatusCode(403);

If you want to return a message, then you must use StatusCode.

answered Jul 14, 2017 at 7:06

juunas's user avatar

juunasjuunas

51.4k13 gold badges113 silver badges144 bronze badges

2

Simply you can use ObjectResult to return a custom response with a status code.

See the syntax,

return new ObjectResult("Message") {StatusCode = YOUR_STATUS_CODE };

Note —
You can pass an object also,

return new ObjectResult(your_model) {StatusCode = YOUR_STATUS_CODE };

Example:

public async Task<IActionResult> Post([FromBody] SomeData _data)
{
     // do your stuff

    // return forbidden with custom message
    return new ObjectResult("Forbidden") { StatusCode = 403};
}

answered Dec 28, 2020 at 7:05

shalitha senanayaka's user avatar

If you don’t return IActionResult as result, you can use the following code :

public List<SomeModel> GetModels()
{
   ... 
   ... // check logic
   ...

   Response.StatusCode = 403;
   return new List<SomeModel>();
}

answered Aug 22, 2019 at 6:19

MOH3N's user avatar

MOH3NMOH3N

8859 silver badges14 bronze badges

1

Having the same issue when migrate from asp net mvc to net core 5. As a decision you can inherit from ObjectResult:

public class ForbidActionResult : ObjectResult
{
    public ForbidActionResult(int statusCode = (int)HttpStatusCode.Forbidden, string errorMessage = null) : 
        base(errorMessage ?? "User is not allowed to enter this page."))
    {
        StatusCode = statusCode;
    }

    public override async Task ExecuteResultAsync(ActionContext context)
    {
        await base.ExecuteResultAsync(context);
    }
}

and return it as IActionResult:

[HttpGet]
public IActionResult Get(int bookId)
{
    var book = dbContext.BookRepository.Find(bookId);

    if (!CurrentUser.CanEditAsClient(book))
    {
        return new ForbidActionResult();
    }

    return Ok();
}

answered Aug 10, 2021 at 10:03

alanextar's user avatar

alanextaralanextar

86410 silver badges16 bronze badges

  • Remove From My Forums
  • Question

  • User1255309776 posted

    Hi,

    I published my project ForOffer to web hosting server using Web deployment method via Visual Studio 2017. I’ve entered all server details and publish was successful. (see

    https://prnt.sc/n1tlmb) .from my side (in Visual Studio)

    But when it opens the page error : 403 Forbidden comes. What might cause this? What I need to check and edit before publishing?

Answers

  • User1255309776 posted

    It finally worked. The problem was that hosting provided didn’t give me the full server name (with port), the server name they gave me today included a port number which helped to connect to database.

    Thank you guys for all your comments and info.

    • Marked as answer by

      Thursday, October 7, 2021 12:00 AM

Обработка ошибок

Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core 7

Последнее обновление: 06.11.2019

Ошибки в приложении можно условно разделить на два типа: исключения, которые возникают в процессе выполнения кода (например, деление на 0), и
стандартные ошибки протокола HTTP (например, ошибка 404).

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

UseDeveloperExceptionPage

Если мы создаем проект ASP.NET Core, например, по типу Empty (да и в других типах проектов), то в классе Startup мы можем найти в начале метода Configure() следующие строки:

if (env.IsDevelopment())
{
	app.UseDeveloperExceptionPage();
}

Если приложение находится в состоянии разработки, то с помощью middleware app.UseDeveloperExceptionPage() приложение перехватывает исключения и
выводит информацию о них разработчику.

Например, изменим класс Startup следующим образом:

public class Startup
{
	public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
	{
		if (env.IsDevelopment())
		{
			app.UseDeveloperExceptionPage();
		}
		app.Run(async (context) =>
		{
			int x = 0;
			int y = 8 / x;
			await context.Response.WriteAsync($"Result = {y}");
		});
	}
}

В middleware app.Run симулируется генерация исключения при делении ноль. И если мы запустим проект, то в браузере мы увидим
информацию об исключении:

Обработка исключений в ASP.NET Core

Этой информации достаточно, чтобы определить где именно в коде произошло исключение.

Теперь посмотрим, как все это будет выглядеть для простого пользователя. Для этого изменим метод Configure:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
	env.EnvironmentName = "Production";
	if (env.IsDevelopment())
	{
		app.UseDeveloperExceptionPage();
	}
	app.Run(async (context) =>
	{
		int x = 0;
		int y = 8 / x;
		await context.Response.WriteAsync($"Result = {y}");
	});
}

Выражение env.EnvironmentName = "Production"; устанавливает режим развертывания вместо режима разработки. В этом случае выражение if (env.IsDevelopment()) будет возвращать false, и мы увидим в браузере что-то наподобие «HTTP ERROR 500»

HTTP ERROR 500 в ASP.NET Core

UseExceptionHandler

Это не самая лучшая ситуация, и нередко все-таки возникает необходимость дать пользователям некоторую информацию о том, что же все-таки произошло. Либо потребуется как-то обработать данную ситуацию.
Для этих целей можно использовать еще один встроенный middleware в виде метода UseExceptionHandler(). Он перенаправляет
при возникновении исключения на некоторый адрес и позволяет обработать исключение. Например, изменим метод Configure следующим образом:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
	env.EnvironmentName = "Production";
	
	if (env.IsDevelopment())
	{
		app.UseDeveloperExceptionPage();
	}
	else
	{
		app.UseExceptionHandler("/error");
	}
	
	app.Map("/error", ap => ap.Run(async context =>
	{
		await context.Response.WriteAsync("DivideByZeroException occured!");
	}));
	
	app.Run(async (context) =>
	{
		int x = 0;
		int y = 8 / x;
		await context.Response.WriteAsync($"Result = {y}");
	});
}

Метод app.UseExceptionHandler("/error"); перенаправляет при возникновении ошибки на адрес «/error».

Для обработки пути по определенному адресу здесь использовался метод app.Map(). В итоге при возникновении исключения будет срабатывать делегат
из метода app.Map.

Error Handling in ASP.NET Core

Следует учитывать, что оба middleware — app.UseDeveloperExceptionPage() и app.UseExceptionHandler()
следует помещать ближе к началу конвейера middleware.

Обработка ошибок HTTP

В отличие от исключений стандартный функционал проекта ASP.NET Core почти никак не обрабатывает ошибки HTTP, например, в случае если ресурс не найден.
При обращении к несуществующему ресурсу мы увидим в браузере пустую страницу, и только через консоль веб-браузера мы сможем увидеть статусный код.
Но с помощью компонента StatusCodePagesMiddleware можно добавить в проект отправку информации о статусном коде.
Для этого добавим в метод Configure() класса Startup вызов app.UseStatusCodePages():

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
	if (env.IsDevelopment())
	{
		app.UseDeveloperExceptionPage();
	}
	
	// обработка ошибок HTTP
	app.UseStatusCodePages();
	
	app.Map("/hello", ap => ap.Run(async (context) =>
	{
		await context.Response.WriteAsync($"Hello ASP.NET Core");
	}));
}

Здесь мы можем обращаться только по адресу «/hello». При обращении ко всем остальным адресам браузер отобразит базовую информацию об ошибке:

UseStatusCodePages в ASP.NET Core

Данный метод позволяет настроить отправляемое пользователю сообщение. В частности, мы можем изменить вызов метода так:

app.UseStatusCodePages("text/plain", "Error. Status code : {0}");

В качестве первого параметра указывается MIME-тип ответа, а в качестве второго — собственно то сообщение, которое увидит пользователь. В сообщение мы можем
передать код ошибки через плейсхолдер «{0}».

Вместо метода app.UseStatusCodePages() мы также можем использовать еще пару других, которые также обрабатываю ошибки HTTP.

С помощью метода app.UseStatusCodePagesWithRedirects() можно выполнить переадресацию на определенный метод, который непосредственно обработает статусный код:

app.UseStatusCodePagesWithRedirects("/error?code={0}");

Здесь будет идти перенаправление по адресу «/error?code={0}». В качестве параметра через плейсхолдер «{0}» будет передаваться статусный код
ошибки.

Но теперь при обращении к несуществующему ресурсу клиент получит статусный код 302 / Found. То есть формально несуществующий ресурс будет существовать, просто статусный код 302
будет указывать, что ресурс перемещен на другое место — по пути «/error/404».

Подобное поведение может быть неудобно, особенно с точки зрения поисковой индексации, и в этом случае мы можем применить другой метод
app.UseStatusCodePagesWithReExecute():

app.UseStatusCodePagesWithReExecute("/error", "?code={0}");

Первый параметр метода указывает на путь перенаправления, а второй задает параметры строки запроса, которые будут передаваться при перенаправлении.
Вместо плейсхолдера {0} опять же будет передаваться статусный код ошибки. Формально мы получим тот же ответ, так как так же будет идти перенаправление на путь «/error?code=404». Но теперь браузер получит оригинальный статусный код 404.

Пример использования:

public void Configure(IApplicationBuilder app)
{
	// обработка ошибок HTTP
	app.UseStatusCodePagesWithReExecute("/error", "?code={0}");

	app.Map("/error", ap => ap.Run(async context =>
	{
		await context.Response.WriteAsync($"Err: {context.Request.Query["code"]}");
	}));

	app.Map("/hello", ap => ap.Run(async (context) =>
	{
		await context.Response.WriteAsync($"Hello ASP.NET Core");
	}));
}

Настройка обработки ошибок в web.config

Еще один способ обработки кодов ошибок представляет собой определение и настройка в файле конфигурации web.config элемента
httpErrors. Этот способ в принципе использовался и в других версиях ASP.NET.
В ASP.NET Core он также доступен, однако имеет очень ограниченное действие. В частности, мы его можем использовать только при развертывании на IIS, а также не можем использовать ряд настроек.

Итак, добавим в корень проекта новый элемент Web Configurarion File, который естественно назовем web.config:

Обработка ошибок в web.config

Изменим его следующим образом:

<?xml version="1.0" encoding="utf-8"?>
<configuration>

  <system.webServer>
	<httpErrors errorMode="Custom" existingResponse="Replace">
      <remove statusCode="404"/>
	  <remove statusCode="403"/>
      <error statusCode="404" path="404.html" responseMode="File"/>
      <error statusCode="403" path="403.html" responseMode="File"/>
	</httpErrors>
   
    <handlers>
      <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified"/>
    </handlers>
    <aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".logsstdout" forwardWindowsAuthToken="false"/>
  </system.webServer>
</configuration>

Также для обработки ошибок добавим в корень проекта новый файл 404.html:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>Ошибка 404</title>
</head>
<body>
    <h1>Ошибка 404</h1>
    <h2>Ресурс не найден!</h2>
</body>
</html>

По аналогии можно добавить файл 403.html для ошибки 403.

Итак, элемент httpErrors имеет ряд настроек. Для тестирования настроек локально, необходимо установить атрибут errorMode="Custom".
Если тестирование необязательно, и приложение уже развернуто для использования, то можно установить значение errorMode="DetailedLocalOnly".

Значение existingResponse="Replace" позволит отобразить ошибку по оригинальному запрошенному пути без переадресации.

Внутри элемента httpErrors с помощью отдельных элементов error устанавливается обработка ошибок. Атрибут statusCode
задает статусный код, атрибут path — адрес url, который будет вызываться, а атрибут responseMode указывает, как будет обрабатываться ответ вызванному url.
Атрибут responseMode имеет значение File, что позволяет рассматривать адрес url из атрибута path как статическую страницу и использовать ее в качестве ответа

Настройки элемента httpErrors могут наследоваться с других уровней, например, от файла конфигурации machine.config. И чтобы удалить
все унаследованные настройки, применяется элемент <clear />. Чтобы удалить настройки для отдельных ошибок, применяется элемент
<remove />.

Для тестирования используем следующий класс Startup:

public class Startup
{
	public void Configure(IApplicationBuilder app)
	{
		app.Map("/hello", ap => ap.Run(async (context) =>
		{
			await context.Response.WriteAsync($"Hello ASP.NET Core");
		}));
	}
}

И после обращения к несуществующему ресурсу в приложении отобразится содержимое из файла 404.html.

Настройка обработки ошибок в web.config в ASP.NET Core

A brief introduction of Problem details

If you have developed HTTP APIs, I’m sure that many times you have had the need to define new error response formats for HTTP APIs to return to your clients. The most common way to do this is using HTTP Status Codes but sometimes is not sufficient to communicate enough information to the clients. For example, imagine a banking HTTP API that allows customers to make online transactions and this call returns Forbidden (403) response telling the client that the customer isn’t allowed to make this transaction, but why? Maybe the customer doesn’t have enough credit? or he has a maximum limit of money to transfer?

To provide additional information to our clients we would need to extend the response body with some kind of document (JSON or XML). The problem I’ve seen in many HTTP APIs is that usually these documents are not the same. It’s very frustating for a client that consumes many HTTP APIs because there isn’t a standard way to deal with these errors and it would need to implement different ways to work with them.

Due to the need to standarize an error response format for HTTP APIs, the Internet Engineering Task Force (IETF) published in March 2016 a document that defines a “problem details” as a way to carry machine-readable details of errors in a HTTP response to avoid the need to define new error response formats for HTTP APIs (Not reinvent the wheel).

Let me show you an example of HTTP response of JSON problem details

HTTP/1.1 403 Forbidden
Content-Type: application/problem+json
Content-Language: en

{
    "type": "https://example.com/probs/out-of-credit",
    "title": "You do not have enough credit.",
    "detail": "Your current balance is 30, but that costs 50.",
    "instance": "/account/12345/msgs/abc",
    "balance": 30,
    "accounts": ["/account/12345","/account/67890"],
    "status": 403
}

The format of the message is application/problem+json media type (It could be application/problem+xml also) and we have several members in the response body:

  • type (string): URI that identifies the problem detail type. In this case “out-of-credit”.
  • title (string): A short human-readable summary about the problem.
  • detail (string): A human-readable explanation about the problem.
  • status (number): HTTP Status Code.
  • instance (string): A URI reference that identifies the specific occurrence of the problem.

We can extend the problem details object with additional members, for example the previous message defines two members “balance” and “accounts” to communicate additional information to the client.

Problem details in ASP.NET Core 2.1

When ASP.NET Core 2.1 came out, the ASP.NET Core team added support for problem details. The class that represents a problem details object is ProblemDetails

An example of use:

[HttpPost]
public ActionResult Transfer()
{
    try
    {
        /// Make a transfer
    }
    catch (OutOfCreditException ex)
    {
        var problemDetails = new ProblemDetails
        {
            Status = StatusCodes.Status403Forbidden,
            Type = "https://example.com/probs/out-of-credit",
            Title = "You do not have enough credit.",
            Detail = "Your current balance is 30, but that costs 50.",
            Instance = HttpContext.Request.Path
        };

        return new ObjectResult(problemDetails)
        {
            ContentTypes = { "application/problem+json" },
            StatusCode = 403,
        };
    }

    return Ok();
}

Problem Details 1

We alse have the ValidationProblemDetails class for validation errors. This class inherits from ProblemDetails and you can see an example in the following code:

[HttpPost]
public ActionResult Transfer(TransferInfo model)
{
    if (!ModelState.IsValid)
    {
        var problemDetails = new ValidationProblemDetails(ModelState);

        return new ObjectResult(problemDetails)
        {
            ContentTypes = { "application/problem+json" },
            StatusCode = 403,
        };
    }

    return Ok();
}

Problem Details 2

The two previous examples have the same problem: They are polluting our controllers (Put your controllers on a diet). IMHO controllers act as mediators: receive the request from the client, transform into a command, send it and response to the client. Let’s see how to move these validations out of controllers into a centralized place.

Model validations

For model validations we need to configure ApiBehaviorOptions in our ConfigureServices:

public void ConfigureServices(IServiceCollection services)
{
    services
        .AddMvc()
        .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

    services.Configure<ApiBehaviorOptions>(options =>
    {
        options.InvalidModelStateResponseFactory = context =>
        {
            var problemDetails = new ValidationProblemDetails(context.ModelState)
            {
                Instance = context.HttpContext.Request.Path,
                Status = StatusCodes.Status400BadRequest,
                Type = $"https://httpstatuses.com/400",
                Detail = ApiConstants.Messages.ModelStateValidation
            };
            return new BadRequestObjectResult(problemDetails)
            {
                ContentTypes =
                {
                    ApiConstants.ContentTypes.ProblemJson,
                    ApiConstants.ContentTypes.ProblemXml
                }
            };
        };
    });
}

We have to remark on two things:

  • The order in which you register the services matter, you must register AddMvc() before configure ApiBehaviorOptions otherwise you won’t see the correct response.

Problem Details 3

  • Your controllers must be decorated with the [ApiController] attribute:
[Route("api/[controller]")]
[ApiController]
public class BankController : ControllerBase

Handle errors

We have seen how to the validation errors works, but we still need to see how to handle exceptions in our application in order to return a problem details message. Thankfully, Kristian Hellang has already created a NuGet package for this purpose Hellang.Middleware.ProblemDetails.

Install-Package Hellang.Middleware.ProblemDetails -Version 3.0.0

Once we have installed it, we need to configure it. Open your Startup class and add the following code to the ConfigureServices method:

public void ConfigureServices(IServiceCollection services)
{
    services
        .AddProblemDetails(setup =>
        {
            setup.IncludeExceptionDetails = _ => Environment.IsDevelopment();
        })

    ...
}

We only include exception details in the problem details messages when we are running in Development mode. It’ll help us to diagnose our HTTP API while we develop.

And finally we need to add problem details to the ASP.NET Core pipeline in Configure method in our Startup class:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app
        .UseProblemDetails()
        .UseMvc();
}

If you want to test it, you can throw an exception in your action controller:

[HttpPost]
public ActionResult Transfer(TransferInfo model)
{
    throw new Exception("Testing problem details");

    return Ok();
}

Run your application and execute the action, you should see the following message:

Problem Details 4

As you can see (In Development mode) we have all the information available related to the exception but if we run our application in non-Development mode all this additional information dissapears:

Problem Details 5

We only need one more thing: What happens if I want to throw my own exceptions and map to custom problem details objects? No problem, You have a method called Map<> to map exceptions to custom problem details objects. Let me show you:

I’ve created a custom OutOfCreditException (This code must be in a service out of our controllers):

[HttpPost]
public ActionResult Transfer(TransferInfo model)
{
    throw new OutOfCreditException(
        "You do not have enough credit.",
        balance: 30,
        cost: 50);

    return Ok();
}

I’ve created also my custom problem details object:

internal class OutOfCreditProblemDetails : ProblemDetails
{
    public decimal Balance { get; set; }
}

The only thing we need left is to configure ProblemDetails how to map this exception with the problem details object. Open Startup.cs and change the method ConfigureServices:

public void ConfigureServices(IServiceCollection services)
{
    services
        .AddProblemDetails(setup =>
        {
            setup.IncludeExceptionDetails = _ => !Environment.IsDevelopment();
            setup.Map<OutOfCreditException>(exception => new OutOfCreditProblemDetails
            {
                Title = exception.Message,
                Detail = exception.Description,
                Balance = exception.Balance,
                Status = StatusCodes.Status403Forbidden,
                Type = exception.Type
            });
        })

    ...

}

Run you app and call the controller action and you should see the following message:

Problem Details 6

Conclusion

In this post I’ve tried to show you a way of specifying errors in HTTP API responses using Problem details and how to avoid to reinvent the wheel in every HTTP API, making easier to our clients handle these messages in a simple and standard way.

Links

Github Hellang.Middleware.ProblemDetails

Понравилась статья? Поделить с друзьями:
  • Asp net application error
  • Asp net 1309 ошибка
  • Asp mvc error 500
  • Asmmap64 sys как исправить ошибку
  • Asmb8 ikvm java error