Страницы

Поиск по вопросам

пятница, 27 декабря 2019 г.

Ограничить доступ для редактирования передаваемой модели в PUT-методе

#c_sharp #шаблоны_проектирования #инспекция_кода #rest #aspnet_web_api


Есть вот такая сущность:

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }        
    public string CategoryName { get; set; } //доступно для редактирования только
пользователю «admin»
    // в реальном проекте свойств больше 
    // и среди них также есть доступные для редактирования только для admin
}


Необходимо на стороне сервера создать метод PUT, который обеспечил бы редактирование
свойства CategoryName только для авторизованного пользователя admin.

Какие практики REST существуют для реализации подобном логики?



Моя реализация такова:

public class ProductDto
{
    [Required]
    public string Name { get; set; }

    [Required]
    public string CategoryName { get; set; }
}

[Authorize]
[RoutePrefix("api/products")]
public class ProductsController : ApiController
{
    private readonly IProductService _productService;

    public ProductsController(IProductService productService)
    {
        _productService = productService;
    }

    [HttpPut]
    [Route("{id}")]
    public HttpResponseMessage Put([FromBody] ProductDto productDto)
    {
        if (!ModelState.IsValid)
        {
            throw new ArgumentException("dto");
        }

        var productId = RequestContext.RouteData.Values["id"].ToString();

        var userName = User.Identity.Name; //извлекаем имя авторизованного пользователя
        var isAdmin = userName == "admin";

        _productService.Update(productId, productDto, isAdmin);

        return Request.CreateResponse(HttpStatusCode.OK);
    }
}

public interface IProductService
{
    void Update(string id, ProductDto dto, bool isAdmin);
}

public class ProductService : IProductService
{
    private readonly IGenericRepository _productRepository;

    public ProductService(IGenericRepository productRepository)
    {
        _productRepository = productRepository;
    }

    public void Update(string id, ProductDto dto, bool isAdmin)
    {
        if (dto == null || id == null)
        {
            throw new ArgumentNullException();
        }

        var product = _productRepository.GetById(id);
        if (product == null)
        {
            throw new ArgumentException(nameof(id));
        }

        product.Name = dto.Name;            
        if(isAdmin)
        {
            product.CategoryName = dto.CategoryName;
        }


        _productRepository.Update(product);
    }
}



Какими изъянами обладает данный код, учитывая то, что входе масштабирования у сущности
Productбудут появляться новые свойства, среди которых также могут быть те которые редактировать
может только admin.
Или стоило попробовать использовать атрибуты валидации/перезагрузку PUT-метода и т.п?

    


Ответы

Ответ 1



Привязывать функционал к имени пользователя не лучшее решение в подобных ситуациях. Для разграничения доступа к функционалу есть специальные средства под названием "роли". Каждому зарегистрированному пользователю можно добавить одну или несколько ролей описывающих его права в системе. Исходя из этого следует второе правило, это разделение прав доступа к функционалу на отдельные методы - "action". В вашем случае первый метод будет вызывать обновление ограниченное количество полей модели, второй метод будет обновлять расширенные поля модели. Конечно для этого придется с клиента вызывать разные методы в зависимости от роли пользователя и в случае нехватки уровня доступа клиентский метод возвратит вменяемую ошибку (403) [RoutePrefix("api/test"), Authorize] public class TestController : ApiController { [HttpPut, Route("{id}")] public void PutAll(int id, [FromBody]BaseModelDto model) { } [HttpPut, Route("{id}/admin"), Authorize(Roles = "admin")] public void PutAdmin(int id, [FromBody]ModelDto model) { } } Что такое роли и как с ними работать можно почитать тут https://habrahabr.ru/post/231807/

Ответ 2



Потенциальное дублирование кода который проверяет что пользователь admin. Можно сделать ActionFilterAttribute и еще на подходе к методу разрешать/запрещать редактирование.

Комментариев нет:

Отправить комментарий