通过软件描述大学时,我遇到了一个身份验证问题。
以前我只有一个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
}
发布于 2019-05-28 07:29:15
对于第一种情况,因为Action根本没有参数,所以更有意义的是返回教师可以访问的学生,或者如果没有人获取特定教师的所有科目,则根本没有学生,所以在这种情况下不需要403。您可以将User
从控制器或inject HttpContextAssessor传递给StudentService,并使用它进行过滤。
对于第二种情况,如果SubjectId
与上下文中的Teacher
不相关,那么返回403是一个完美的情况。如果您不介意为每个请求从数据库中获取数据,您可以在基于策略的授权中使用Requirement组合AuthorizationHandler,方法是从数据库中检索授权所需的任何数据,从而确定教师是否有权访问某些科目。实现该目标的步骤:
首先在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中加入基于策略的属性。如果这不起作用,那么将属性放在控制器中肯定会起作用。
希望这能有所帮助。
发布于 2019-05-27 19:24:04
您的场景非常实用,这使得这个问题非常有趣。但如果你看看这个documentation就好了。
使用声明授予教师对他们必须能够访问的信息的访问权限。您可以将申请另存为.i.e。"TeacherName-TargetInforNameTheyCanAccess";根据教师应该可以访问的信息量,您可以拥有尽可能多的声明。
这对学生也是一样的。可以为该讲师班级下的学生创建报销申请。例如:"StudentName-LectureName“,然后您可以通过检查学生是否声称属于特定的讲师班级来建立您的身份验证基础。
https://stackoverflow.com/questions/56324892
复制相似问题