REST. Один GET запрос для разных ролей

292
24 августа 2017, 18:18

Есть три роли: admin, area(оператор района) и school(оператор школы).

Имена area-пользователей совпадают с Id из таблицы Area базы данных. Имена school-пользователей совпадают с Id из таблицы School базы данных.

area-пользователи должны иметь доступ только к студентам своего района, т.е. имя area-пользователя и StudentDto.AreaId должны совпадать. school-пользователи должны иметь доступ только к студентам своей школы, т.е. имя school-пользователя и StudentDto.SchoolId должны совпадать.

А теперь код:

public class Student
{
    public string Surname { get; set; }
    public string Name { get; set; }        
    public string SchoolId { get; set; }
    public virtual School School { get; set; }
}
public class School
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int AreaId { get; set; }
    public virtual Area Area { get; set; }
}    
public class Area
{
    public int Id { get; set; }
    public int Name { get; set; }
}
public class StudentDto
{
    public string Id { get; set; }
    public string Surname { get; set; }
    public string Name { get; set; }
    public int SchoolId { get; set; }
    public int AreaId { get; set; }
}
public interface IStudentService
{
    IEnumerable<StudentDto> GetAll(int? areaId, int? schoolId);
}
[RoutePrefix("api/students")]        
public class StudentsController : ApiController
{
    private readonly IStudentService _studentService;
    public StudentsController(IStudentService studentService)
    {
        _studentService = studentService;
    }
    [HttpGet]
    public IHttpActionResult GetAll(int? areaId, int? schoolId)
    {
        var studentDtos = _studentService.GetAll(areaId: areaId, schoolId: schoolId);
        var authorizedUser = User.Identity.Name;
        if (User.IsInRole("school"))    
        {
            if (!studentDtos.All(dto => dto.SchoolId.ToString() == authorizedUser))
            {
                return StatusCode(HttpStatusCode.Forbidden);
            }
        }
        if (User.IsInRole("area"))
        {
            if (!studentDtos.All(dto => dto.AreaId.ToString() == authorizedUser))
            {
                return StatusCode(HttpStatusCode.Forbidden);
            }
        }
        return Ok(studentDtos);
    }
}

Вопрос

Хочется чтобы URI получения списка студентов для всех трех типов пользователей был одинаков GET: .../api/students, как я понимаю так и должно быть согласно REST (если это не так, то подправьте).

Насколько правильно все сделал я в выше описанном коде, не слишком ли нагружен метод контроллера? В частности интересует, что говорит "хорошая практика" о том как выполнена валидация?

Я также рассматривал вариант создания кастомного атрибута (фильтр) или создание отдельных URI для каждого типа пользователя, типа: api/students/admin, api/students/area, api/students/school. С кастомным атрибутом я так и не разобрался, т.к. на входе нельзя валидировать список студентов - ведь его сначала надо получить (или ничего страшного если получение организовать в самом фильтре?). А касаемо отдельных URI, то как писал выше, то это уже не REST.

Answer 1
GET: .../api/students

Да, это соответствует REST naming guidelines

Если быть точнее то вам надо таки писать:

GET: .../api/students?role=school

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

READ ALSO
Потокобезопасная коллекция с#

Потокобезопасная коллекция с#

ПриветИскал инфу про потокобезопасную коллекцию и почти везде такой код:

297
Создание View из Controller MVC

Создание View из Controller MVC

ASP занимаюсь недавно поэтому прошу сильно не битьЕсть небольшое приложение на asp MVC в котором нужно вывести на страничку некоторый список

289
Невозможность скрыть Label

Невозможность скрыть Label

Есть 3 лэйблы, 2 из который надо скрытьДелаю это не через XAML, почему не спрашивайте

249