3

我有一个业务要求,即只在我们的响应负载中发送许可的属性。例如,我们的响应 DTO 可能有几个属性,其中之一是 SSN。如果用户没有查看 SSN 的权限,那么我绝不希望它出现在 Json 响应中。第二个要求是,如果客户端有权查看或更改属性,我们发送空值。由于第二个要求,将用户无法查看的属性设置为 null 将不起作用。我仍然必须返回空值。

我有一个可行的解决方案。我通过我的 DTO 反射创建了一个 expandoObject,并且只添加了我需要的属性。这在我的测试中有效。

我看过实现 ITextSerializer。我可以使用它并将我的响应 DTO 包装在另一个具有要跳过的属性列表的对象中。然后我可以推出我自己的 SerializeToString() 和 SerializeToStream()。在这一点上,我真的没有看到任何其他方式。我不能使用 JsConfig 并制作 SerializeFn,因为要跳过的属性会随着每个请求而改变。

所以我认为实现 ITextSerializer 是一个不错的选择。有没有很好的例子来实现这一点?我真的很想利用序列化程序中已经完成的所有艰苦工作,并利用出色的性能。我认为在理想的世界中,我只需要在 WriteType.WriteProperties() 中添加一个检查即可查看,并且该属性是要写入的,但这是内部的,实际上,它们中的大多数都是所以我真的无法接受他们的优势。

如果有人有一些见解,请告诉我!也许我正在使 ITextSerialzer 的实现变得更加困难,实际上是这样吗?

谢谢!

拉取请求#359将属性“ExcludePropertyReference”添加到 JsConfig 和 JsConfigScope。您现在可以像我需要的那样排除范围内的引用。

4

1 回答 1

0

我会犹豫是否要编写自己的序列化器。我会尝试找到可以插入现有 ServiceStack 代码的解决方案。这样您就不必担心更新 dll 和中断更改。

一种可能的解决方案是使用自定义属性来装饰您的属性,您可以反映并隐藏属性值。这甚至可以在序列化发生之前在服务中完成。这仍然包括他们用户无权查看的值,但我认为如果你将这些属性清空,它们甚至不会被 JSON 序列化。如果您保持所有属性相同,您将保留强类型 DTO 的好处

这是我很快想出的一些 hacky 代码来演示这一点。我会将它移动到一个插件中,并通过某种属性缓存使反射更快,但我想你会明白的。

使用以下路线点击 url 两次以查看它的实际效果。

  • /测试?角色
  • /test?role=Admin(伪装成经过身份验证的请求)
[System.AttributeUsage(System.AttributeTargets.Property)]
公共类 SecureProperty : System.Attribute
{
    公共字符串角色 {get;set;}

    公共 SecureProperty(字符串角色)
    {
        角色=角色;
    }
}

[路线(“/测试”)]
公共类测试:IReturn
{
    公共字符串名称 { 获取;放; }

    [安全属性(“管理员”)]
    公共字符串 SSN { 获取;放; }

    公共字符串 SSN2 { 获取;放; }

    公共字符串角色 {get;set;}
}

公共类TestService:服务
{
    公共对象获取(测试请求)
    {   
        // 破解演示角色。
        var usersCurrentRole = request.Role;

        var props = typeof(Test).GetProperties()
        。在哪里(
            prop => ((SecureProperty[])prop
                .GetCustomAttributes(typeof(SecureProperty), false))
                .Any(att => att.Role != usersCurrentRole)
        );

        var t = 新测试() {
            名称=“乔”,
            SSN = "123-45-6789",
            SSN2 = "123-45-6789" };

        foreach(道具中的var p){
            p.SetValue(t, "xxx-xx-xxxx", null);
        }

        返回 t;
    }
}

Require().StartHost("http://localhost:8080/",
    configurationBuilder: 主机 => { });

我在ScriptCS中创建了这个演示。一探究竟。

于 2013-07-27T15:50:49.783 回答