我正在构建相当复杂的REST API。整个API受身份验证保护。
系统中的任何人都应该可以访问某些资源(比如说,Person
),但是我想“隐藏”特定用户角色的某些字段。
假设Person
资源有以下字段:
FirstName
LastName
BirthDate
Address
我希望对于HRManager
个角色的用户可以看到所有这些内容,为Address
隐藏JuniorHRManager
并为其他人留下FirstName
+ LastName
这种RESTful方法是根据应用于登录用户的角色的规则从响应中删除字段吗? 这是最简单的实现我猜(因为我使用了一个优秀的ServiceStack,它有全局响应过滤器),但我不确定这是否不会破坏REST规则?
我到目前为止唯一想到的另一种方法是创建特定于角色的资源(比如PersonForHRManager等)。但是这将是荒谬的,因为系统应该具有各种可见和组合的组合。角色的隐藏字段。
答案 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资源。我看到两种可能的策略:
为每个角色实施不同的RESTful服务,这是您建议的策略。这很难维护,正如您可能理解的那样。
实现一个RESTful服务,该服务返回所有角色,但您必须在形成每个属性值时检查授权。例如,在为服务器端的属性Address
设置要返回的值时,必须检查用户的角色。如果用户是HRManager
,您将返回正确的值。如果用户是JuniorHRManager
,则必须将特定属性返回为空,或者使用相应的消息指示不允许用户访问特定属性。这种策略可以更容易维护,具体取决于用于实现Web服务的服务器端技术(我不知道您使用的是哪种)。例如,在.NET中,您可以为每个属性使用属性,以指示哪些授权角色可以访问特定属性。如果您使用.NET,this和this教程可以提供一些额外的指导。
希望我帮忙!