我正在构建相当复杂的REST API.整个API受身份验证保护.Person
系统中的任何人都应该可以访问某些资源(例如,比方说),但是我想"隐藏"特定用户角色的某些字段.
假设Person
资源有以下字段:
FirstName LastName BirthDate Address
我想他们都对用户可见与HRManager
角色,隐藏Address
了JuniorHRManager
,留下FirstName
+ LastName
其他人.
这种RESTful方法是根据应用于登录用户的角色的规则从响应中删除字段吗? 这是最简单的实现我猜(因为我使用的是一个具有全局响应过滤器的优秀ServiceStack ),但我不确定这是否会破坏REST规则?
我到目前为止唯一想到的另一种方法是创建特定于角色的资源(比如PersonForHRManager等).但是,这将是荒谬的,因为系统应该具有角色的可见和隐藏字段的各种组合.
我同意你的方法,响应过滤器可能是做到这一点的最佳解决方案; 并使用描述所需角色的属性简单地标记响应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[])
我没有测试过上面的代码,所以它可能不完美,但它应该非常接近.
我希望这有帮助.