关于c#:在特定参数未满足要求的情况下,限制授权或减少结果

Restrict authorization or reduce result in case specific parameter arent satisfy requirements

通过软件描述大学我遇到身份验证问题。

以前,我只有一个Headmaster角色,该角色可以执行和访问任何操作。
但是就目前而言,我需要集成一个Teacher角色。

Teacher角色应该具有访问某些功能的选项,这些功能很容易受Authorize属性限制。但在某些情况下,我想减少此角色允许访问的数据数量,例如并非宇宙的所有学生,而是学习Teacher's Subject的学生。

所有这些都已在EF中进行了描述(例如,教师与受试者,学科与学生之间的关系)。但是现在我努力拒绝(返回403)对Teacher

不允许访问的学科或学生的请求。

我考虑过我的服务使用规范模式的原因,因此将使用规范的过滤器来减少生成的数据,因为这有助于减少数据量(有时减少为无数据),但并不能完全拒绝请求。

能否请您提供一个链接或体系结构的想法,以满足对上面指定的两个用例的期望?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// 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
}


在第一种情况下,由于该操作根本没有任何参数,因此更有意义的是让教师可以访问的学生返回,或者如果没有人接受某位老师的所有科目,则根本没有学生返回,因此在这种情况下不需要403。您可以从控制器传递User或将HttpContextAssessor注入到StudentService并将其用于过滤。

对于第二种情况,

如果SubjectId与上下文中的Teacher不相关,则返回403的理想情况。如果您不介意为每个请求从数据库中获取数据,则可以通过从数据库中检索所需的任何数据来在基于策略的授权中使用Requirement组合AuthorizationHandler,从而确定教师是否可以访问某些学科。实现它的步骤:

首先在Startup.ConfigureServices中为Teachers-Subjects关系和处理程序设置策略:

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

接下来为该策略创建AuthorizationHandler:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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类,它只是一个空类:

1
2
3
4
public class TeacherSubjectRequirement: IAuthorizationRequirement
{

}

由于我们正在AuthorizationHandler中进行授权机制,因此可以将此类保留为空。但是,仍需要基于策略的授权才能起作用。

然后为使该策略生效,将属性添加到控制器

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

但是,老实说,我没有尝试将基于策略的属性放入Action中。如果这不起作用,则将属性放入控制器中肯定会起作用。

希望这会有所帮助。


您的情况非常实际,这使问题变得非常有趣。但是,很高兴您阅读此文档。

使用声明使教师可以访问他们必须能够访问的信息。您可以将索赔另存为。 " TeacherName-TargetInforName他们可以访问";您可以根据老师应获取的信息量来拥有尽可能多的主张。

这对学生也是一样。您可以为该讲师班级下的学生创建索赔。就像说:"" StudentName-LectureName ",然后您可以通过检查学生是否声称自己属于特定的讲师班来进行认证。