Ограничить авторизацию или уменьшить результат в случае, если конкретный параметр не удовлетворяет требованиям - PullRequest
3 голосов
/ 27 мая 2019

Описание университета с помощью программного обеспечения. Я столкнулся с проблемой аутентификации.

Раньше у меня была только роль Headmaster, которая может делать и получать доступ ко всему.Но сейчас мне нужно интегрировать роль Teacher.

Роль Teacher должна иметь возможность доступа к определенным функциям, которые могут быть легко ограничены атрибутом Authorize.Но в некоторых случаях я хочу уменьшить количество данных, доступ к которым разрешен для этой роли, например, не все студенты вселенной, а те, кто изучает Teacher's Subject.

Все этоуже описано в EF, (например, отношения учителя-предмета, субъекта-ученика).Но теперь я изо всех сил пытаюсь отклонить (вернуть 403) запрос на предмет или студентов, которым не разрешен доступ по Teacher.

Я подумал об использовании шаблона Спецификации для моих Услуг, поэтому результирующие данные будут уменьшеныс фильтром спецификации, так как он помогает уменьшить объем данных, иногда до отсутствия данных, но не помогает полностью отклонить запрос.

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

// entity models
class Subject {
    ...
    public Teacher Teacher { get; set; }
    public List<Students> { get; set; }
    ...
}

class Teacher {
    ...
    public List<Subject> Subjects { get; set; }
    ...
}
class Student {
    ...
    public List<Subject> StudiedSubjects {get; set; }
    ...
}

// first use-case I want to solve
public ActionResult<List<Student>> GetStudent()
{
    // previously I just did
    return Ok(_studentsService.GetStudents());

    // but as for now in case of Teacher role accessed the method I want to
    // reduce the number of returned students
}

// second use-case I want to solve
public ActionResult<Subject> GetSubjectDetails(int subjectId)
{
    // previously I just did
    return Ok(_subjectService.GetSubject(subjectId);

    // but as for now in case of Teacher role I need to check whether its
    // allowed to get the subject and return Access denied in case its not
}

Ответы [ 2 ]

3 голосов
/ 28 мая 2019

Для вашего первого случая, потому что в действии вообще нет параметров, будет более целесообразно возвращать учеников, которые доступны для учителя, или вообще не иметь учеников, если никто не изучает все предметы определенного учителя, поэтому403 не нужны в этом случае.Вы можете передать User из контроллера или ввести HttpContextAssessor в StudentService и использовать его для фильтрации.

как и во втором случае, идеальная ситуация - вернуть 403, если SubjectIdне имеет отношения к Teacher в контексте.Если вы не возражаете против получения данных из базы данных для каждого запроса, вы можете использовать Требование в сочетании AuthorizationHandler в авторизации на основе политик, получая любые данные, необходимые для авторизации из базы данных, таким образом, чтобы определить,учитель имеет доступ к определенным предметам.Шаги для достижения этой цели:

Сначала настройте политику для отношения Teachers-Subjects и обработчики в Startup.ConfigureServices:

services.AddAuthorization(options =>
{
    options.AddPolicy("TeacherSubject", policy => policy.Requirements.Add( new TeacherSubjectRequirement() ));
});
services.AddScoped<IAuthorizationHandler, TeacherSubjectHandler>();

, затем создайте AuthorizationHandler для этой политики:

public class TeacherSubjectHandler : AuthorizationHandler<TeacherSubjectRequirement>
{
    readonly IHttpContextAccessor _contextAccessor;
    readonly UserManager<AppUser> _usermanager;
    readonly UserToTeacherService _userToTeacherService;

    public ThePolicyAuthorizationHandler(IHttpContextAccessor c, UserManager<AppUser> u, _userToTeacherService s)
    {
        _contextAccessor = c;
        _userManager = u;
        _userToTeacherService = s;
    }

    protected override async Task HandleRequirementAsync(AuthorizationHandlerContext authHandlerContext, TeacherSubjectRequirement requirement)
    {
        var user = _userManager.GetUserAsync(_contextAccessor.HttpContext.User);
        var teacher = _userToTeacherService(user); //I assume this service will also retrieve teacher's subjects
        var subjectIds = teacher.Subjects.Select(s => s.SubjectId).ToList();

        if (context.Resource is AuthorizationFilterContext filterContext)
        {
            var subjectIdStr = filterContext.RouteData.Values["id"].ToString();
            if ( int.TryParse(subjectIdStr, out var subjectId) && subjectIds.Contains(subjectId) )
            {
                context.Succeed(requirement);
            }

        } 

    }
}

Что касается класса Requirement, это просто пустой класс:

public class TeacherSubjectRequirement: IAuthorizationRequirement
{

}

Поскольку мы делаем механизм авторизации в AuthorizationHandler, мы можем оставить этот класс пустым.Но это все еще будет необходимо для авторизации на основе политик.

А затем, чтобы политика вступила в силу, добавьте атрибут к контроллеру

[Authorize(Policy = "TeacherSubject")]
public ActionResult<Subject> GetSubjectDetails(int subjectId)
{
    //existing code
}

Но, честно говоря, я не пробовал помещать атрибут на основе политики в действие.Если это не работает, размещение атрибута в контроллере, безусловно, будет работать

Надеюсь, это поможет.

0 голосов
/ 27 мая 2019

Ваш сценарий очень практичен, что делает вопрос очень интересным.Но было бы неплохо, чтобы вы ознакомились с этой документацией .

. Используйте заявки, чтобы предоставить преподавателю доступ к информации, к которой он должен иметь доступ.Вы можете сохранить заявку как .ie "TeacherName-TargetInforNameTheyCanAccess";у вас может быть столько заявлений, сколько возможно, в зависимости от того, сколько информации должно быть доступно учителю.

То же самое относится и к ученикам.Вы можете создавать заявки на студентов, которые подпадают под этот класс лекторов.Как, например, сказать: «StudentName-LectureName», и затем вы можете основать свою аутентификацию, проверив, заявлен ли студент в определенном классе лекторов.

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