c# - 在特定参数不满足要求的情况下限制授权或减少结果
问题描述
通过软件描述大学时我遇到了一个身份验证问题。
以前我只有一个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
}
解决方案
对于您的第一种情况,因为 Action 根本没有参数,所以返回可供教师访问的学生会更有意义,或者如果没有人参加某个教师的所有科目,则根本没有学生,所以 403 不是在这种情况下需要。您可以传递User
from 控制器或将 HttpContextAssessor 注入StudentService 并将其用于过滤。
至于您的第二种情况,如果与上下文SubjectId
无关,则返回 403 是一个完美的情况Teacher
。如果您不介意从数据库中获取每个请求的数据,您可以在基于策略的授权中使用Requirement组合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
}
但老实说,我还没有尝试将基于策略的属性放在 Action 中。如果这不起作用,将属性放在控制器中肯定会起作用。
希望这可以帮助。
推荐阅读
- python - 计算有条件的组内的共享元素
- physics - 有没有办法编写 LabView VI 在 DIO 线上进行慢速转换?
- docker - 如何在 Windows Docker Desktop 中更改 docker 子网
- python - 如何使用 python 从打印的菜单中获取用户选择的值?
- javascript - React CDN,有没有办法异步加载脚本?
- http - 运行 Go 服务器时,persistConn 会打开什么?
- python - 使用 Python 解析 XML 属性
- python - 用特定数值替换 Python 列表中的字符串值
- javascript - 使用动态变量从字符串中反应渲染 html
- python - 调用这个记忆函数会引发 TypeError: unhashable type: 'dict'