草庐IT

c# - 如何保护 Web API 免受数据检索而不是来自资源所有者的数据检索

coder 2024-05-23 原文

我有一个 asp.net web api。

我想稍后在一个 Azure 网站上自行托管我的 Web API。

登录用户可以在浏览器中执行此操作 /api/bankaccounts/3

获取有关银行帐号 3 的所有详细信息

但登录用户不是银行帐号3的所有者。

我必须如何设计我的 Controller 及其背后的服务

在数据库中用户只能检索/修改自己的资源吗?

更新

在我创建一个之后:

public class UserActionsAuthorizationFilter : AuthorizationFilterAttribute
{
   public override void OnAuthorization(HttpActionContext actionContext)
   {
       if (actionContext != null)
       { 
           bool canUserExecuteAction = IsResourceOwner(actionContext);
           // stop propagation  
       }
   }

private bool IsResourceOwner(HttpActionContext actionContext)
        {
            var principal = (ClaimsPrincipal)Thread.CurrentPrincipal; 
            var userIdAuthenticated = Convert.ToInt32(principal.Claims.Single(c => c.Type == ClaimTypes.Sid).Value);

            int targetId = Convert.ToInt32(actionContext.Request.GetRouteData().Values["Id"]);
            var requstScope = actionContext.ControllerContext.Request.GetDependencyScope();
            var service = (ISchoolyearService)requstScope.GetService(typeof(ISchoolyearService));
            bool canUserExecuteAction = service.HasUserPermission(userIdAuthenticated, targetId);
            return canUserExecuteAction;
        }
}

现在的问题是 IsResouceOwner 被硬编码到某个服务 => SchoolyearService 因此绑定(bind)到 Schoolyear SQL 表

我需要让 IsResourceOwner 方法对所有具有字段 UserId/UserEmail 的 sql 表保持通用。

问题是 - 我真的认为没有人这样做 - 我必须在 HasUserPermission 方法中将每个资源所有者检查映射到正确的 Sql 表。

映射应该是什么样子的?

检查 Controller 名称“SchoolyearController”因此要检查的表是“schoolyear”表?太荒谬了。

这个自定义属性“UserActionsAuthorizationFilter”将出现在每个“数据” Controller 上。

无论用户触发什么 Controller url 来获取数据,在我必须检查他是否是资源所有者之前。

我想我无法在过滤器中决定这一点。

我必须让数据检索/修改通过 Controller ,并在数据检索完成之前在存储库中进行 ResourceOwner 检查。

你怎么看这个:

API

public async Task<IHttpActionResult> Delete(int id)
{
   var result = await service.Delete(id, User.Identity.UserId);
    if (result == 0)
        return NotFound();
    return Ok();
}

repo

    public async Task<int> Delete(int id, int userId)
    {
        var schoolyerToDelete = await context.Schoolyears.SingleOrDefaultAsync(s => s.Id == id && s.UserId == userId); 

// If schoolyearToDelete is null nothing is removed, thus the affected rows are ZERO.
        context.Schoolyears.Remove(schoolyerToDelete);
       return await context.SaveChangesAsync();
    }
  • 对于错误的 UserId,Get 方法不会返回任何内容
  • 对于 Create 方法:没问题,如果登录,每个人都应该能够创建资源。
  • 对于 Update 方法:与 Delete 方法相同,学年由 id 和 UserId 检索。

一般来说,我存储库中的每个方法都应该考虑 CRUD 操作中的 UserId。

你怎么看?

最佳答案

这是一个老问题,但对于遇到类似问题的任何人,这里有一个可能的解决方案。

添加一个抽象层

  • 您可以像以前一样使用 UserActionsAuthorizationFilter 来凑合;只需执行以下操作
  • 让你所有的服务接口(interface)(比如 ISchoolyearService)继承一个定义了 HasUserPermission 的通用接口(interface)
public interface IService {
  HasUserPermission(int32 userIdAuthenticated, int targetId));}

public interface ISchoolyearService : IService {
  /* Include all other methods except for HasUserPermission */
}
  • 在 UserActionsAuthorizationFilter 中,添加一个字段:“internal IService ServiceProvider”
  • 在 UserActionsAuthorizationFilter 中,修改 IsResourceOwner():

来自

var service = (ISchoolyearService)requstScope.GetService(typeof(ISchoolyearService));

var service = (IService)requstScope.GetService(this.ServiceProvider);
- Then, change all the attributes on your Controllers to specify which type of IService they use
[UserActionsAuthorizationFilter(ServiceProvider = typeof(ISchoolyearService))] <br> internal SchoolyearController : Controller { }

这种方法的显着缺点是您随后 promise 仅允许用户访问通过 HasUserPermission() 检查的用户,因此您无法进行任何操作应该可以公开访问的更深层次的 URL,例如 /api/testresults/3/public

P.S> 你是对的,根据 Controller 名称找出要检查哪个 SQL 表是荒谬的?

关于c# - 如何保护 Web API 免受数据检索而不是来自资源所有者的数据检索,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30817347/

有关c# - 如何保护 Web API 免受数据检索而不是来自资源所有者的数据检索的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  3. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  4. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  5. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  6. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  7. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  8. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  9. ruby - 如何每月在 Heroku 运行一次 Scheduler 插件? - 2

    在选择我想要运行操作的频率时,唯一的选项是“每天”、“每小时”和“每10分钟”。谢谢!我想为我的Rails3.1应用程序运行调度程序。 最佳答案 这不是一个优雅的解决方案,但您可以安排它每天运行,并在实际开始工作之前检查日期是否为当月的第一天。 关于ruby-如何每月在Heroku运行一次Scheduler插件?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/8692687/

  10. ruby-on-rails - 如何从 format.xml 中删除 <hash></hash> - 2

    我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为

随机推荐