Ser*_*gey 5 c# .net-core asp.net-core
通过软件描述大学时我遇到了身份验证问题。
以前我只有一个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
}
Run Code Online (Sandbox Code Playgroud)
对于您的第一种情况,因为操作根本没有参数,所以返回教师可以访问的学生更有意义,或者如果没有人学习特定教师的所有科目,则根本没有学生,因此 403 不是在这种情况下需要。您可以传递Userfrom 控制器或将 HttpContextAssessor 注入到 StudentService 并使用它进行过滤。
至于你的第二种情况,如果 the与上下文SubjectId无关,那么返回 403 是一个完美的情况。Teacher如果您不介意为每个请求从数据库获取数据,您可以在基于策略的授权中使用需求组合AuthorizationHandler,通过从数据库检索授权所需的任何数据来确定教师是否有权访问某些主题。实现它的步骤:
首先设置教师-科目关系和处理程序的策略Startup.ConfigureServices:
services.AddAuthorization(options =>
{
options.AddPolicy("TeacherSubject", policy => policy.Requirements.Add( new TeacherSubjectRequirement() ));
});
services.AddScoped<IAuthorizationHandler, TeacherSubjectHandler>();
Run Code Online (Sandbox Code Playgroud)
接下来为该策略创建 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);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
至于 Requirement 类,它只是一个空类:
public class TeacherSubjectRequirement: IAuthorizationRequirement
{
}
Run Code Online (Sandbox Code Playgroud)
由于我们在 AuthorizationHandler 中进行授权机制,因此可以将此类留空。但基于策略的授权仍然需要它才能发挥作用。
然后为策略生效,给控制器添加属性
[Authorize(Policy = "TeacherSubject")]
public ActionResult<Subject> GetSubjectDetails(int subjectId)
{
//existing code
}
Run Code Online (Sandbox Code Playgroud)
但说实话,我还没有尝试过将基于策略的属性放入 Action 中。如果这不起作用,将属性放入控制器肯定会起作用。
希望这可以帮助。
| 归档时间: |
|
| 查看次数: |
679 次 |
| 最近记录: |