RESTful是否限制每个经过身份验证的用户角色的资源的字段可见性?

时间:2013-12-26 09:30:15

标签: web-services api rest design-patterns servicestack

我正在构建相当复杂的REST API。整个API受身份验证保护。 系统中的任何人都应该可以访问某些资源(比如说,Person),但是我想“隐藏”特定用户角色的某些字段。

假设Person资源有以下字段:

FirstName
LastName
BirthDate
Address

我希望对于HRManager个角色的用户可以看到所有这些内容,为Address隐藏JuniorHRManager并为其他人留下FirstName + LastName

这种RESTful方法是根据应用于登录用户的角色的规则从响应中删除字段吗? 这是最简单的实现我猜(因为我使用了一个优秀的ServiceStack,它有全局响应过滤器),但我不确定这是否不会破坏REST规则?

我到目前为止唯一想到的另一种方法是创建特定于角色的资源(比如PersonForHRManager等)。但是这将是荒谬的,因为系统应该具有各种可见和组合的组合。角色的隐藏字段。

2 个答案:

答案 0 :(得分:8)

我同意你的方法,响应过滤器可能是做到这一点的最佳解决方案;并使用描述所需角色的属性简单地标记响应DTO。我还没有看到更好的方法来进行属性级权限。

根据角色从响应中删除属性是完全可以接受的,如果它是公共API,请确保记录人们在每个角色中可以期待的属性。

响应过滤器,在您的AppHost中:

this.ResponseFilters.Add((req, res, dto) => {

    // Get the roles you are permitted to access. You will need to store these in the request Items collection
    var roles = (from r in req.Items where r.Key == "Roles" select r.Value).FirstOrDefault() as string[];

    // Get the type of the response dto
    var dtoType = dto.GetType();

    // Loop through the properties
    foreach(var property in dtoType.GetPublicProperties()){

        // Ignore properties that are read-only
        if(!property.CanWrite)
            continue;

        // Get all the role attributes on the property
        var attributes = property.GetCustomAttributes(typeof(RequireRoleAttribute), false) as RequireRoleAttribute[];

        // Get all the permitted roles
        var permittedRoles = new List<string>();
        foreach(var attribute in attributes)
            permittedRoles.AddRange(attribute.Roles);

        // Check if there are specific permitted roles assigned to this attribute
        if(permittedRoles.Count != 0)
        {
            bool permitted = false;

            // Check if check require role against roles we may have.
            foreach(var role in permittedRoles){
                if(roles.Contains(role))
                {
                    // We have a matching role
                    permitted = true;
                    break;
                }
            }

            // No permission to the property
            if(!permitted) {
                var type = property.GetType();

                // Set the field to a default value.
                property.SetValue(dto, null);
            }
        }
    }
});

属性:

public class RequireRoleAttribute : Attribute
{
    public string[] Roles { get; set; }
    public RequireRoleAttribute(params string[] roles) { Roles = roles; }
}

在DTO上:

[RequireRole("Spiderman","Superman","Batman")]
public string Address { get; set; }

备注:

  • 您需要将允许的角色保存到request.Items.Add("Roles", string[])
  • 我没有测试过上面的代码,所以它可能不完美,但应该非常接近。

我希望这会有所帮助。

答案 1 :(得分:3)

我认为你做对了。 RESTful服务只不过是简单的HTTP请求。因此,您必须保护整个http资源。我看到两种可能的策略:

  1. 为每个角色实施不同的RESTful服务,这是您建议的策略。这很难维护,正如您可能理解的那样。

  2. 实现一个RESTful服务,该服务返回所有角色,但您必须在形成每个属性值时检查授权。例如,在为服务器端的属性Address设置要返回的值时,必须检查用户的角色。如果用户是HRManager,您将返回正确的值。如果用户是JuniorHRManager,则必须将特定属性返回为空,或者使用相应的消息指示不允许用户访问特定属性。这种策略可以更容易维护,具体取决于用于实现Web服务的服务器端技术(我不知道您使用的是哪种)。例如,在.NET中,您可以为每个属性使用属性,以指示哪些授权角色可以访问特定属性。如果您使用.NET,thisthis教程可以提供一些额外的指导。

  3. 希望我帮忙!