Проблема разработки веб-API - не позволяет пользователям использовать PUT / PATCH для обновления идентификатора пользователя - PullRequest
0 голосов
/ 07 ноября 2018

У меня возникла небольшая проблема с дизайном, связанная с тем, как запретить пользователям обновлять поле идентификатора пользователя в данных, публикуемых в API. Я использую ASP.Net Core 2.1 и Entity Framework Core. Этот API будет использоваться с веб-приложением (я тоже буду его создавать), и для обоих приложений потребуется аутентификация и авторизация политики.

У меня есть класс событий, который ссылается на то, кем был пользователь, который его создал (идентификатор пользователя + свойство навигации пользователя для моей сущности пользователя). Каждый раз, когда API вызывается с помощью PUT / PATCH / DELETE, я хочу запретить пользователям возможность обновлять поле идентификатора пользователя и удалять события других пользователей.

API можно вызывать со всеми глаголами HTTP, например, запросом GET на api/events для получения списка всех событий или запросом POST на api/events для создания события.

Моя сущность события:

public Guid Id { get; set; }
public string Title { get; set; }
public string Message { get; set; }   
public string Url { get; set; }
public DateTime Created { get; set; }
public DateTime ScheduledTime { get; set; }
public Guid UserId { get; set; }
public User CreatedBy { get; set; }

Модель данных обновления событий (для запросов PUT / PATCH):

public string Title { get; set; }
public string Message { get; set; }
public string Url { get; set; }
public DateTime? ScheduledTime { get; set; }

Мой пользовательский объект

public Guid Id { get; set; }
public string Email { get; set; }
public List<Event> Events { get; set; } = new List<Event>();

Маршрут для моего контроллера очень прост: [Route("api/[controller]")], поэтому к нему обращается api/events.

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

т.е. Мое действие по обновлению в API:

[HttpPut("{id}")]
public async Task<IActionResult> UpdateEvent([FromRoute] Guid id, [FromQuery] Guid userId,[FromBody] EventUpdateDto eventToUpdate)
{
//compare userId passed to action by fetching event from database and compare values
//return 403 if not equal else continue
}

Проблема в том, что я использую как параметры маршрута, так и параметры строки запроса. Я могу упростить маршрут до {eventid}/{userid}, но я не знаю, является ли это наилучшей практикой. Это будет означать, что я вызываю мой API, чтобы обновить определенное событие, а затем углубиться в конкретного пользователя, что не имеет особого смысла. Я также не хотел идти другим путем api/{userid}/events/{eventid} для моего контроллера, потому что я хочу получить доступ ко всем событиям для всех пользователей или одному событию в моем веб-приложении - я не хочу, чтобы оно ограничивалось только событиями извлечения для одного пользователя.

У меня также есть та же проблема с DELETE, поскольку я не хочу, чтобы пользователь удалял сообщения других пользователей. Так что его настройки, как показано ниже:

[HttpDelete("{id}")]
public async Task<IActionResult> DeleteEvent([FromRoute] Guid id, [FromQuery] Guid userId)

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

1) Удалите все проверки для проверки идентификатора пользователя из API и поместите логику в веб-приложение, которое будет вызывать API. При таком подходе каждый раз, когда пользователь пытается отредактировать событие в приложении, мне сначала нужно извлечь событие из API, сравнить текущий идентификатор пользователя с идентификатором пользователя, полученным из API, и либо позволить им продолжить, либо выдать ошибку. Единственная проблема, с которой я столкнулся, заключалась в том, что вместо одного (вместо события «сначала извлекается событие», а затем, возможно, после события) должна быть проведена дополнительная поездка к API. При таком подходе моя модель обновления событий может безопасно содержать поле ИД пользователя, и я могу упростить мой вызов API без параметра строки запроса.

2) Немного измените мой подход выше, чтобы не использовать параметры строки запроса и использовать только параметры маршрута. Вместо вызова api/events/1?id=1 измените его так, чтобы оно выглядело как api/events/1/1, где первый параметр - это идентификатор события, а второй - идентификатор пользователя. Я чувствую, что создание URL-адресов такого типа будет проще в приложении, но отклонится от правильной практики REST.

3) Сохраняйте мой текущий подход.

Я немного сомневаюсь в подходе № 1 из-за возможных проблем с производительностью, а также из-за необходимости иметь отдельный API, чтобы его можно было подключать к другим приложениям без необходимости писать сложную логику в веб-приложении. Один подход лучше другого? Есть ли лучший подход, который я могу использовать при проектировании моих моделей наружной облицовки? Любая помощь по дизайну будет очень полезна.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...