如果特定参数无法满足要求,则限制授权或减少结果 [英] Restrict authorization or reduce result in case specific parameter arent satisfy requirements

查看:108
本文介绍了如果特定参数无法满足要求,则限制授权或减少结果的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



以前我只有一个校长角色,可以做任何事情。
但就目前而言,我需要集成 Teacher 角色。



Teacher 角色应该具有访问某些功能的选项,该功能可以通过 Authorize 属性轻松限制。但是在某些情况下,我想减少此角色允许访问的数据数量,例如不是所有的宇宙学生,而是学习老师 主题的学生。



所有这些都已经在EF中进行了描述(例如,教师与受试者,学科与学生之间的关系)。但是,现在我很难拒绝(返回403)对老师不允许访问的学科或学生的要求。



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



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

  //实体模型
类Subject {
...
public Teacher Teacher {get;组; }
公共列表< Students> {得到;组; }
...
}

班级教师{
...
public List< Subject>主题{get;组; }
...
}
班级学生{
...
public List< Subject>研究对象{get;组; }
...
}

//我要解决的第一个用例
public ActionResult< List< Student>> GetStudent()
{
// //之前我只是
返回Ok(_studentsService.GetStudents());

//但就目前而言,在访问教师角色的情况下,我要
// //减少返回学生的数量
}

//我要解决的第二个用例
public ActionResult< Subject> GetSubjectDetails(int subjectId)
{
//之前我只是
返回Ok(_subjectService.GetSubject(subjectId);

//但现在的教师角色,我需要检查其
//是否允许获取该主题并返回访问权限,以防其不是
}


解决方案

对于第一种情况,由于Action根本没有任何参数,因此让学生返回可供老师使用,如果没有人同时学习某位老师的所有科目,则根本没有学生可以使用,因此在这种情况下不需要403。您可以通过 User 控制器或将HttpContextAssessor 注入StudentService,并使用它进行过滤。



对于第二种情况,返回403的理想情况如果 SubjectId 与上下文中的 Teacher 不相关。如果您不介意为每个请求从数据库获取数据,则可以使用要求组合 AuthorizationHandler ,方法是从数据库中检索您需要进行授权的任何数据,从而确定教师是否可以访问某些学科。实现它的步骤:



首先在 Startup.ConfigureServices 中为教师-主题关系和处理程序设置策略。 :

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

接下来为该策略创建AuthorizationHandler:

 公共类TeacherSubjectHandler:AuthorizationHandler< TeacherSubjectRequirement> 
{
只读IHttpContextAccessor _contextAccessor;
只读UserManager< AppUser> _usermanager;
只读UserToTeacherService _userToTeacherService;

public ThePolicyAuthorizationHandler(IHttpContextAccessor c,UserManager< AppUser> u,_userToTeacherService s)
{
_contextAccessor = c;
_userManager = u;
_userToTeacherService = s;
}

受保护的重写异步任务HandleRequirementAsync(AuthorizationHandlerContext authHandlerContext,TeacherSubjectRequirement要求)
{
var user = _userManager.GetUserAsync(_contextAccessor.HttpContext.User);
var教师= _userToTeacherService(用户); ///我假设此服务还将检索老师的科目
var subjectIds = Teacher.Subjects.Select(s => s.SubjectId).ToList();

if(context.Resource是AuthorizationFilterContext filterContext)
{
var subjectIdStr = filterContext.RouteData.Values [ id]。ToString();
if(int.TryParse(subjectIdStr,out var subjectId)&& subjectIds.Contains(subjectId))
{
context.Succeed(requirement);
}

}

}
}

至于Requirement类,它只是一个空类:

 公共类TeacherSubjectRequirement:IAuthorizationRequirement 
{

}

由于我们在AuthorizationHandler,我们可以将此类保留为空。但是,基于策略的授权仍然需要工作。



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

  [Authorize(Policy = TeacherSubject)] 
public ActionResult< Subject> GetSubjectDetails(int subjectId)
{
//现有代码
}

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



希望这会有所帮助。


Describing University via software I faced an auth issue.

Previously I had only a Headmaster role, which can do and access anything. But as for now, I need to integrate a Teacher role.

The Teacher role should have an option to access certain features, which could be easily restricted by Authorize attribute. But in some cases, I want to reduce the number of data allowed to access for this role, e.g. not all students of the universe, but the ones who study Teacher's Subject.

All of this is already described in EF, (e.g. teacher-subject, subject-students relationships). But now I struggle to refuse (return 403) request for subject or students which are not allowed to access by Teacher.

I thought about a Specification pattern usage for my Services, so the resulting data will be reduced with a Specification's filter, as it helps reduce the data amount, sometimes to no-data, but didn't help to fully refuse a request.

Could you kindly provide me a link or an architectural idea to satisfy expectations for both use-cases specified above?

// 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
}

解决方案

For your first case, because the Action have no parameters at all, it'll make more sense to return Students that are accessible for a Teacher, or no Students at all if no one take all the subjects of certain Teacher, so 403 are not needed in this case. You could pass the User from controller or inject HttpContextAssessor to StudentService and use it for filtering.

as for your second case, its a perfect situation to return 403 if the SubjectId is not related to the Teacher in context. If you dont mind getting data from database for each request, you can use Requirement combined AuthorizationHandler in a Policy-Based Authorization by retrieving any data you need for authorization from database thus determine if the teacher has access to certain Subject(s). Steps to achieve it:

First setup the policy for the Teachers-Subjects relation and the handlers in Startup.ConfigureServices :

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

next create the AuthorizationHandler for that policy:

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

        } 

    }
}

as for the Requirement class, its just an empty class:

public class TeacherSubjectRequirement: IAuthorizationRequirement
{

}

Since we're doing the authorization mechanism in AuthorizationHandler, we can leave this class empty. But it will still needed for the policy-based authorization to works.

And then for the policy to take effect, add attribute to the controller

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

But to be honest, I haven't tried putting policy-based attribute in an Action. If this doesn't work, putting the attribute in controller will surely works.

Hope this helps.

这篇关于如果特定参数无法满足要求,则限制授权或减少结果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆