Net Core动态模型绑定

时间:2017-10-31 04:35:47

标签: c# authentication asp.net-core authorization

我正在尝试建立一个不仅基于用户的授权系统 - >权限 - >角色 - >群体,但也在实体 - >属性。

所以我想在post和put请求中限制模型绑定,这样我就可以验证用户有权更新或创建哪些属性,然后让他/她更新或创建实体......否则拒绝请求。

也许这个想法过于复杂,但我想拥有与某些CMS在线相同的功能。

我正在阅读,也许这可以通过自定义模型Binder解决,我正在学习很多但是,我想知道这是“正确的道路”还是可能有更快或更好的方法它

非常感谢你,我会不断用代码更新我的问题,所以也许可以帮助将来有同样想法的人。

1 个答案:

答案 0 :(得分:0)

我正在做同样的事情,我相信完全有可能使用自定义[Attributes]执行此操作。这是我在动态选择语句中完成它的一个小实现:

首先,我有一个自定义属性,它将枚举UserRoles作为输入:

[AttributeUsage(AttributeTargets.Property)]
public class RestrictUserRoles : Attribute
{
    public RestrictUserRoles(UserRoles roles)
    {
        Roles = roles;
    }

    public UserRoles Roles { get; }
}

UserRoles-enum可以这样实现:

[Flags]
public enum UserRoles
{
    [Description("Administrator")]
    Admin = 1,
    [Description("Employee")]
    Employee = 2,
    [Description("Head of a division")]
    DivisionHead = 4,
    [Description("Fired")]
    Fired = 8
}

我使用枚举,因为有些员工可能是管理员,部门负责人(甚至被解雇)。

然后我有一个IQueryable扩展,它获取用户有权查看的所有属性,并将这些属性与所选属性相交。为此,我使用动态Linq和反射。

public static class QueryableExtensions
{
    public static IQueryable SelectProperties<T>(this IQueryable<T> source, UserRoles roles, string criteria)
    {
        // get all the properties that a user is authorized to see
        var authenticatedProperties = typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public)
            .Where(prop => prop.CustomAttributes.Any(attr =>
                attr.AttributeType == typeof(RestrictUserRoles) &&
                (((RestrictUserRoles) Attribute.GetCustomAttribute(prop, typeof(RestrictUserRoles))).Roles & roles) !=
                0))
            .Select(prop => prop.Name)
            .ToList();

        // if there aren't any, then the user is not
        // authorized to view any properties
        // DISCLAIMER: or someone has forgotten to mark any properties
        // with the RestrictUserRoles-attribute
        if (!authenticatedProperties.Any()) throw new UnauthorizedAccessException();

        // we get all the properties that the user wants to 
        // select from the string that was passed to the function in 
        // the form Prop1, Prop2, Prop3
        var selectProperties = criteria
            .Split(',')
            .Select(property => property.Trim());

        // Get the intersection between these properties, IE we
        // select only those properties that the user has selected
        // AND is authorized to view
        var properties = authenticatedProperties
            .Intersect(selectProperties)
            .ToList();

        // if there are none that intersect, return all those
        // properties that a user is authorized to view
        if (!properties.Any()) properties = authenticatedProperties;

        // run the query using dynamic linq
        return source.Select("new(" + properties.JoinToString(",") + ")");
    }
}

这不是经过现场测试的,但它应该可以解决这个问题并且很容易扩展到突变。

编辑:忘了我使用扩展函数来加入我在下面定义的所有属性:

public static string JoinToString(this IEnumerable<string> list, string delimiter = "")
{
    return string.Join(delimiter, list);
}