在特定参数不满足要求的情况下限制授权或减少结果



通过软件描述大学时,我遇到了一个身份验证问题。

以前我只有一个Headmaster角色,它可以做和访问任何事情。 但就目前而言,我需要整合一个Teacher角色。

Teacher角色应该有一个访问某些功能的选项,这些功能很容易被Authorize属性限制。但在某些情况下,我想减少允许访问此角色的数据数量,例如,不是宇宙的所有学生,而是研究Teacher'sSubject的学生。

所有这些都已经在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
}

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

至于您的第二种情况,如果SubjectId与上下文中的Teacher无关,则返回 403 是一个完美的情况。如果您不介意从数据库中获取每个请求的数据,则可以在基于策略的授权中使用要求组合授权处理程序,方法是从数据库中检索授权所需的任何数据,从而确定教师是否有权访问某些科目。实现它的步骤:

首先为教师-科目关系和Startup.ConfigureServices中的处理程序设置策略:

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

接下来,为该策略创建授权处理程序:

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

至于需求类,它只是一个空类:

public class TeacherSubjectRequirement: IAuthorizationRequirement
{
}

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

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

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

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

希望这有帮助。

你的场景非常实用,这使得这个问题非常有趣。但是,最好看看这个文档。

使用声明向教师授予对他们必须能够访问的信息的访问权限。您可以将声明保存为 .i.即"教师姓名-目标InforNameThey CanAccess";您可以拥有尽可能多的声明,具体取决于教师应访问多少信息。

学生也是如此。您可以为该讲师课程下的学生创建声明。比如说:"学生姓名-讲座名称",然后您可以通过检查学生是否声称属于特定的讲师课程来建立身份验证。

最新更新