3 votes

Restreindre l'autorisation ou réduire le résultat dans le cas où un paramètre spécifique ne satisfait pas aux exigences.

Décrivant l'université via un logiciel, j'ai été confronté à un problème d'authentification.

Auparavant, je n'avais qu'un Headmaster qui peut faire et accéder à tout. Mais pour l'instant, j'ai besoin d'intégrer une Teacher rôle.

En Teacher devrait avoir la possibilité d'accéder à certaines fonctions, qui pourraient être facilement restreintes par les personnes suivantes Authorize attribut. Mais dans certains cas, je veux réduire le nombre de données auxquelles ce rôle est autorisé à accéder, par exemple, pas tous les étudiants de l'univers, mais ceux qui étudient Teacher's Subject .

Tout ceci est déjà décrit dans EF, (par exemple, les relations professeur-sujet, sujet-étudiants). Mais maintenant, j'ai du mal à refuser (retour 403) les demandes pour les sujets ou les étudiants qui ne sont pas autorisés à accéder par Teacher .

J'ai pensé à l'utilisation d'un modèle de spécification pour mes services, de sorte que les données résultantes seront réduites avec le filtre d'une spécification, car il aide à réduire la quantité de données, parfois à aucune donnée, mais n'a pas aidé à refuser complètement une demande.

Pourriez-vous me fournir un lien ou une idée d'architecture permettant de répondre aux attentes pour les deux cas d'utilisation spécifiés ci-dessus ?

// 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
}

3voto

riza Points 566

Dans le premier cas, puisque l'action n'a aucun paramètre, il sera plus logique de renvoyer les étudiants qui sont accessibles pour un enseignant, ou aucun étudiant si personne ne prend toutes les matières d'un certain enseignant, donc 403 ne sont pas nécessaires dans ce cas. Vous pouvez passer le paramètre User du contrôleur ou injecter HttpContextAssessor à StudentService et l'utiliser pour le filtrage.

quant à votre deuxième cas, c'est une situation parfaite pour retourner 403 si le SubjectId n'est pas liée à la Teacher dans le contexte. Si cela ne vous dérange pas de récupérer les données de la base de données pour chaque demande, vous pouvez utiliser Exigence combiné Gestionnaire d'autorisation dans une autorisation basée sur une politique en récupérant toutes les données dont vous avez besoin pour l'autorisation dans la base de données afin de déterminer si l'enseignant a accès à certains sujets. Étapes à suivre pour y parvenir :

Commencez par configurer la politique pour la relation Enseignants-Sujets et les gestionnaires dans Startup.ConfigureServices :

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

Créez ensuite l'AuthorizationHandler pour cette politique :

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);
            }

        } 

    }
}

quant à la classe Requirement, c'est juste une classe vide :

public class TeacherSubjectRequirement: IAuthorizationRequirement
{

}

Puisque nous faisons le mécanisme d'autorisation dans AuthorizationHandler, nous pouvons laisser cette classe vide. Mais elle sera toujours nécessaire pour que l'autorisation basée sur la politique fonctionne.

Et ensuite, pour que la politique prenne effet, ajoutez l'attribut au contrôleur

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

Mais pour être honnête, je n'ai pas essayé de mettre un attribut basé sur une politique dans une action. Si cela ne fonctionne pas, mettre l'attribut dans un contrôleur fonctionnera sûrement.

J'espère que cela vous aidera.

0voto

Mosia Thabo Points 11

Votre scénario est très pratique, ce qui rend la question très intéressante. Mais il serait bien que vous regardiez ceci documentation .

Utilisez les revendications pour donner à l'enseignant l'accès aux informations auxquelles il doit pouvoir accéder. Vous pouvez enregistrer une revendication sous le nom de .i.e. "Nomduprofesseur-Nomd'objetIlspeuventAccéder" ; vous pouvez avoir autant de revendications que possible en fonction de la quantité d'informations auxquelles le professeur doit avoir accès.

Il en va de même pour les étudiants. Vous pouvez créer des demandes pour les étudiants qui sont sous la classe de ce professeur. Comme dire : "Nom de l'étudiant-Nom du cours" et vous pouvez ensuite baser votre authentification en vérifiant si l'étudiant est revendiqué comme appartenant à une classe de professeurs spécifique.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X