验证/操作多租户 Web API 中的输入参数

2024-05-18

假设我们有一个多租户博客应用程序。该应用程序的每个用户可能拥有多个由该服务托管的博客。

我们的 API 允许读取和写入博客文章。在某些情况下,指定 BlogId 是可选的,例如,获取用 ASP.NET 标记的所有帖子:

/api/posts?tags=aspnet

如果我们想查看某个网站上所有带有 ASP.NET 标签的帖子specific博客,我们可以要求:

/api/posts?blogId=10&tags=aspnet

一些API方法require有效的 BlogId,例如创建新博客文章时:

POST: /api/posts
{
    "blogid" : "10",
    "title" : "This is a blog post."
}

BlogId 需要在服务器上进行验证,以确保它属于当前(经过身份验证的)用户。我也想要infer如果请求中未指定,则为用户的默认 blogId(为简单起见,您可以假设默认是用户的第一个博客)。

我们有一个IAccountContext包含当前用户信息的对象。如果需要的话可以注射。

{
    bool ValidateBlogId(int blogId);
    string GetDefaultBlog();
}

在 ASP.NET Web API 中,推荐的方法是:

  1. 如果在消息正文或 uri 中指定了 BlogId,请验证它以确保它属于当前用户。如果没有则抛出 400 错误。
  2. 如果请求中未指定 BlogId,则从以下位置检索默认 BlogIdIAccountContext并使其可供控制器操作使用。我不希望控制器知道这个逻辑,这就是为什么我不想打电话IAccountContext直接来自我的行动。

[Update]

经过 Twitter 上的讨论并考虑到 @Aliostad 的建议,我决定将博客视为一种资源,并将其作为我的 Uri 模板的一部分(因此始终是必需的),即

GET api/blog/1/posts -- get all posts for blog 1
PUT api/blog/1/posts/5 -- update post 5 in blog 1

我用于加载单个项目的查询逻辑已更新为按帖子 id 和博客 id 加载(以避免租户加载/更新其他人的帖子)。

剩下要做的唯一一件事就是验证 BlogId。遗憾的是我们不能在 Uri 参数上使用验证属性,否则 @alexanderb 的建议会起作用。相反,我选择使用 ActionFilter:

public class ValidateBlogAttribute : ActionFilterAttribute
{
    public IBlogValidator Validator { get; set; }

    public ValidateBlogAttribute()
    {
        // set up a fake validator for now
        Validator = new FakeBlogValidator();
    }

    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        var blogId = actionContext.ActionArguments["blogId"] as int?;

        if (blogId.HasValue && !Validator.IsValidBlog(blogId.Value))
        {
            var message = new HttpResponseMessage(HttpStatusCode.BadRequest);
            message.ReasonPhrase = "Blog {0} does not belong to you.".FormatWith(blogId);
            throw new HttpResponseException(message);
        }

        base.OnActionExecuting(actionContext);
    }
}

public class FakeBlogValidator : IBlogValidator
{
    public bool IsValidBlog(int blogId)
    {
        return blogId != 999; // so we have something to test
    }
}

验证 blogId 现在只是装饰我的控制器/操作的一个例子[ValidateBlog].

几乎每个人的答案都对解决方案有所帮助,但我已将答案标记为 @alexanderb,因为它没有耦合控制器内的验证逻辑。


恐怕这可能不是您正在寻找的答案类型,但它可能会为讨论增添一些谦虚的内容。

你会看到你正在经历的所有麻烦并跳过所有的圈子,因为你需要推断blogId?我认为这就是问题所在。 REST 是无状态的,而您似乎在服务器上持有一个单独的状态(上下文),这与 HTTP 的无状态性质发生冲突。

BlogId 当是操作的一个组成部分时,需要明确地成为资源标识符的一部分 - 因此我将它简单地放在 URL 中。如果你不这样做,这里的问题是URL/URI并不真的uniquely识别资源 - 与名称所暗示的不同。如果John访问该资源时看到的资源与之前不同Amy does.

这将简化设计,这也很有意义。当设计正确时,一切都会很好地发挥作用。我努力追求简单.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

验证/操作多租户 Web API 中的输入参数 的相关文章

随机推荐

  • React Native glog iOS:未知类型名称“_START_GOOGLE_NAMESPACE_”

    我已经构建了一个 React Native 的 Android 项目 它运行良好 然后我开始了 iOS 部分 我正在使用react native cli 2 0 1react native 0 60 4和Xcode 10和Mac OS Mo
  • 检查 JavaScript 文件是否已加载

    首先 这不是这个的重复question https stackoverflow com questions 4036203 check if javascript file was loaded 您很快就会明白原因 我有一个文件想要在我的H
  • 获取函数的命名空间

    我正在开发一个包 我希望在其中向对象添加编辑历史记录 该包允许其他包注册用于编辑对象的函数 我正在寻找一种方法来记录注册用于编辑的函数的包的版本 问题是 给定一个函数 如何从导出的位置获取包 我的想法是调查它的搜索路径 但是search 仅
  • 大多数 Linux 系统头文件与 C++ 兼容吗?

    大多数 Linux 系统头文件 API C 兼容吗 今天我试图做这样的事情 include
  • 使用 MacPorts 在 Mac OS X 10.5 上安装 PostgreSQL 时出错

    我已经使用 MacPorts 在几台不同的计算机上安装了 PostgreSQL 没有问题 但是当涉及到我自己的笔记本电脑时 我无法构建它 当我执行此命令时 sudo port install postgresql83 我收到此错误 chec
  • Internet Explorer 中的锯齿状按钮边缘

    如何去除 Internet Explorer 中宽按钮的锯齿状边缘 例如 您还可以通过设置来消除 Windows XP 的按钮样式 以及 Windows 的所有其他版本 background color and or border colo
  • 自定义 UITableViewCell 选择样式?

    当我点击我的UITableViewCell 当我单击单元格时 背景部分 我的背景图像未覆盖的区域 会变成蓝色 另外 所有的UILabel单击时单元格上的 s 变为白色 这就是我想要的 然而 我不想要的是当我点击它时的蓝色背景 但如果我这样做
  • 限制实体框架中子实体的数量

    底线在前 有没有一种简洁的方法可以限制可以属于实体框架中父级的子实体的数量 我现在使用的是4 3 1 问题 我正在开发一个 ASP NET MVC3 站点 它通过使用实体框架的数据访问层访问数据 我有一个 SearchList 实体 它与搜
  • 通过代理服务器连接到 WCF 服务时出现奇怪的异常

    例外 相对 URI 不支持此操作 发生在以下情况 我有一个 WCF 服务 ServiceContract ProtectionLevel ProtectionLevel None public interface IMyService Op
  • 如何更改 OxyPlot Y 轴字符串格式?

    谁能告诉我如何更改 Y 轴字符串格式 我想向 Y 轴百分比添加百分号 我正在使用 OxyPlot 在 wpf 中生成图表 这是我的尝试 但它不起作用 Func
  • HTML5 仅拖放图像

    我想做的是 如果所有拖动的文件都是图像 则将其删除 但如果有其他文件扩展名 则不要删除它们 而仅删除图像 这是我的尝试 HTML div div JavaScript var dropzone document getElementById
  • 在 Laravel 中动态设置数据库连接和语言

    我有 3 个域指向同一个Laravel应用 我想要的是每个人都连接到自己的数据库并根据 TLD 加载自己的语言文件 我可以在哪个文件中设置这些设置 我可以直接在配置文件中执行此操作 或者可以在加载配置之前执行某些事件 我拥有的是一个简短的函
  • web3.eth.sendSignedTransaction() 总是返回“返回错误:nonce 太低”

    I used 电子邮件受保护 cdn cgi l email protection在 Node js 中与私有区块链交互 我是按照官方文档写的代码 电子邮件受保护 cdn cgi l email protection var Web3 re
  • Rails/Ruby 合并两个具有相同键、不同值的哈希值

    我有两个想要合并的哈希值 它们看起来像这样 Hello gt 3 Hi gt 43 Hola gt 43 第二个哈希看起来像 Hello gt 4 Hi gt 2 Bonjour gt 2 我想合并这两个哈希数组 使结果看起来像 Hello
  • 为什么Boost的`bcp smart_ptr dir/`复制了6MB的源代码?

    所以我想从 boost 中分离出智能指针来在我的项目中使用 并且我被引导使用bcp公用事业 今天我把它编译并做了bcp smart ptr to copy to my project 结果 6MB 代码to copy to my proje
  • Arbor Js - 节点 Onclick?

    我在用着arbor js http arborjs org 创建图表 我如何创建一个onclick节点的事件 或者在单击时在某处创建节点链接 Arborjs org 主页的节点在单击时链接到外部页面 我如何复制它 或者使节点在单击时调用 j
  • 在带有 Storyboard 的 XCode 4 中以模态方式推送视图时,出现“对开始/结束外观转换的不平衡调用”警告

    在网上进行了一些研究但没有成功后 我来这里向您询问有关我的警告的问题 实际上 我有一个带有导航控制器的视图 V1 我想在 V1 完成加载时推送模态视图 V2 所以我用performSegueWithIdentifier方法 我正在使用故事板
  • C# 接收和发送数据

    我仍在努力改进我之前写的东西 现在我在接收数据时遇到了问题 我有一个程序 用于使用 tcpClient 将字符串发送到正在侦听指定端口的程序 它工作正常 所以我决定再发送一次数据 public static void receiveThre
  • 使用数据库中的项目填充复选框列表?

    好的 所以我想将一些数据填充 绑定到复选框列表 但似乎无法绑定正确的值 我想用 ROW 中的信息填充它 而不是我所发生的整个列 无论如何 这里有一些代码可以向您展示问题所在 这是xaml中的代码
  • 验证/操作多租户 Web API 中的输入参数

    假设我们有一个多租户博客应用程序 该应用程序的每个用户可能拥有多个由该服务托管的博客 我们的 API 允许读取和写入博客文章 在某些情况下 指定 BlogId 是可选的 例如 获取用 ASP NET 标记的所有帖子 api posts ta