WebAPI的一个常见用例是使用MVC控制器呈现shell视图,其中包含javascript然后命中您的API以访问数据。
但是,让我们说您有一些昂贵的API操作,并且您不希望人们远程访问这些端点 - 您只希望您的应用程序提供的MVC视图访问它们。你怎么能保护它们?
在这种情况下,Request.IsLocal
无法正常工作,因为javascript正在其计算机上的客户端浏览器中调用它。即使它确实有效,你需要挖掘才能获得真正的HttpContext
才能找到这个属性 - 而且这个解决方案在自托管的WebAPI中不起作用。
对于需要有效IPrincipal
的API端点,您可以使用[Authorize]
属性保护它们。但是,您希望应用能够为匿名用户访问的API端点呢?
我尝试了一个解决方案,并将其单独发布作为答案,因为我不确定它是否是最佳(甚至是好的)方法。
答案 0 :(得分:2)
如果您的MVC站点使用身份验证,则可以为Web API方法启用表单身份验证。您可以编写一个自定义[Authorize]
属性,该属性将检查是否存在将从AJAX调用发送的表单身份验证cookie,如果存在则构造主体。
另一种可能的解决方案是使用tokens
保护您的API,这是一种更加RESTful的风格。这里的想法是,当用户在您的MVC网站上进行身份验证时,您可以生成令牌并将其传递给视图,该令牌将在向Web API发送AJAX请求时使用,后者将验证令牌及其签名的有效性。
另一方面,如果您的网站不使用身份验证,那么事情会变得非常复杂,因为您无法知道请求是否来自受信任的客户端,因为您使用的是javascript来调用API方法。
答案 1 :(得分:2)
在你开始讨论“你尝试过什么”之前,我已经尝试过了。有用。只是不确定是否有更好的方法。
创建MVC操作过滤器,并在Application_Start
期间将其添加为全局过滤器。
创建一个Http(WebAPI)操作过滤器,并将其用于应拒绝远程请求的操作。
全局MVC过滤器执行此操作:
在请求中查找特定的Cookie。如果cookie在那里,则其值被解密。解密后的值应该是DateTime
的字符串表示形式,因此请使用DateTime.TryParse
将其删除。如果该值已正确解析为DateTime
,并且DateTime
不到一天,则停止此处,不执行任何其他操作。
如果cookie不存在,或者无法解密/解析,或者超过一天,请向浏览器写一个新的cookie。使用当前DateTime.UtcNow.ToString()
作为值,对其进行加密,然后使用HttpOnly = false
进行编写。
WebAPI过滤器执行此操作:
在请求中查找特定的Cookie。如果cookie在那里,请解密其值并尝试将其解析为DateTime
。
如果该值为有效DateTime
并且不到2天,请停止此处,不做任何其他操作。
否则,抛出403 Forbidden异常。
关于我目前执行此操作的几点说明。首先,我使用AES加密共享秘密和盐。共享密钥在web.config中存储为appSetting
。对于salt,我启用了匿名标识并使用Request.AnonymousID
作为salt。我并不完全喜欢盐,因为在WebAPI控制器中使用它是一种琐事,但只要它不是自托管的,就不是不可能的。