我想简单地从控制器检查另一个 URL 是否已授权。
例如,我想像这样调用一个控制器:
[HttpPost]
public ActionResult IsUrlAuthorized(string url)
{
bool isAuthorized = // What do I put here?
return Json(isAuthorized);
}
所以我想知道我可以调用什么来检查当前用户是否有权使用传入的 URL。我猜答案与路由有关,它位于 MVC 之外?
这是一个有点相似的问题,但不完全相同:
ASP.NET MVC。检查用户是否已从 JavaScript 获得授权
因为用户通常可能会或可能不会被授权,但可能没有正确的权限或角色分配来查看特定的 URL。
有想法吗?
更新:我使用标准 MVC 授权属性来锁定我的应用程序,因此我将在这里给出一个示例。在 MVC 中,路由映射到控制器。控制器上的单个方法可以限制为一个或多个角色:
public class HomeController : Controller
{
[Authorize(Roles = "User, Moderator")]
public ActionResult ListRecentPosts()
{
. . .
}
}
或者,整个控制器可以限制为一个或多个角色:
[Authorize(Roles = "Admin")]
public class AdminController : Controller
. . .
这些控制器方法中的任何一个响应的实际 URL 都基于标准 MVC 中的默认映射app:
routes.MapRoute("Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
但是,您可以善待您的用户,并通过添加更多路由来使 URL 可猜测 - 因此,控制器方法可以有许多指向它的名称。您不能仅仅从 URL 中假设和推断控制器名称(即使站点中一半的 URL 都是这样映射的)。
因此,想必我要么需要一种方法来直接询问路由引擎当前用户是否授权了某个 URL,要么需要分两步询问路由引擎哪个控制器和方法,然后询问它们是否被授权 - 希望不是通过使用直接反射和匹配角色似乎又假设了太多。
更新 2:出现此问题的方式是我的应用程序顶部有一个帐户条。可以通过选择您被授权的多个帐户之一来更改其状态。根据您在应用程序中所处的位置,您选择的帐户可能有权查看此页面 - 并且您可能正在填写不想丢失的表单。因此,天真的方法 - 当他们选择另一个帐户时刷新 - 是有害的,并且浪费用户的时间,即使没有表单并且他们只是阅读一个全是文本的页面。
虽然这种便利对用户来说很好,但用户会公平地认为他们作为不应该获得权限的用户而看不到的页面确实被拒绝了(并且,将它们留在禁止的页面上是有害的) - 从中采取的行动将会失败)。所以我需要知道是否根据他们的新权限重定向。
我喜欢 .Net 的原因之一是它的许多最好的库分解得非常好,因此您可以轻松地重新组合属于其正常功能或新功能一部分的内容。路由模块和 MVC 看起来都构建得很好,所以我不得不怀疑这是可以完成的。
廉价的黑客方法是确保我的授权模块在用户未获得授权时返回一致的重定向状态代码,并且当用户在帐户条中更改其帐户时,触发 2 个 AJAX 调用:一个用于更改帐户,然后第二个通过 AJAX 访问当前页面只是为了检查 HTTP 状态代码。 200 OK 表示保持页面不变,Redirect 表示遵循重定向。显然,这有点难看,涉及额外的 HTTP 调用,在日志中创建错误命中,并假设如何在应用程序中处理授权。
可能还有第二个问题 - 该页面可能已获得授权,但只需更改其工作方式或外观即可。这个特定的应用程序的外观没有基于帐户的变化(除了帐户条本身),我可以通过提供表单侦听的自定义事件来处理功能更改 - 他们可以从服务器重新加载任何相关数据以响应它。
I'd like to simply check from a Controller whether another URL is authorized.
So for example, I'd like to call into a Controller like so:
[HttpPost]
public ActionResult IsUrlAuthorized(string url)
{
bool isAuthorized = // What do I put here?
return Json(isAuthorized);
}
So I'd like to know what I could call to check on whether the current user is authorized for the passed-in URL or not. I'm guessing the answer has something to do with Routes, which sit a little bit outside MVC?
This is a somewhat similar question but not quite the same thing:
ASP.NET MVC. Check if user is authorized from JavaScript
Since the user may or may not be authorized in general, but may not have the right permissions or role assignments to see a specific URL.
Ideas?
Update: I use standard MVC authorization attributes to lock down my app, so I'll just give an example of what that looks like here. In MVC Routes map to Controllers. A single method on a Controller can be restricted to one or more Roles:
public class HomeController : Controller
{
[Authorize(Roles = "User, Moderator")]
public ActionResult ListRecentPosts()
{
. . .
}
}
Or, an entire Controller can be restricted to one or more roles:
[Authorize(Roles = "Admin")]
public class AdminController : Controller
. . .
The actual URL that any of these controller methods responds to is based on a default mapping in a standard MVC app:
routes.MapRoute("Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
But, you can be nice to your users and make URLs guessable by adding a lot more Routes - as a result, a Controller method can have many names that point to it. You can't just assume and infer the controller name from the URL (even if it maps out that way for half the URLs in the site).
So presumably I either need a way to ask the Routing engine directly whether a URL is authorized for the current user, or a 2-step of asking the Routing engine for which Controller and Method, then ask if those are authorized - hopefully not by using Reflection and matching Roles directly as that again would appear to assume too much.
Update 2: The way this came up is I have an Account strip at the top of my app. Its state can change by selecting one of several accounts you're authorized as. Depending on where you are in the app, the account you chose might have authorization to view this page - and you might be in the middle of filling out a form you don't want to lose. So the naive approach - just refresh when they pick another account - is harmful, and a waste of the user's time even if there is no form and they're just reading a page that's all text.
While that convenience to the user is nice, the user is going to fairly assume that pages they can't see as a user who shouldn't have permission really are denied (and, it would be harmful to leave them on a page that's forbidden - actions taken from it will fail). So I need to know whether to redirect away based on their new permissions.
One of the things I love about .Net is the way many of its best libraries decompose so well, so you can easily recompose things that are part of its normal functionality, or a new twist. Both the Routing module and MVC appear to be very well constructed, so I have to suspect this can be done.
The cheap hack is to ensure that my authorization module returns a consistent redirect status code when a user isn't authorized, and when the user changes their account in the account strip, fire 2 AJAX calls: One to change account, and then a second to the current page over AJAX just to check the HTTP Status Code. 200 OK means leave the page as is, Redirect means follow the redirect. Obviously this is a little ugly, involves an extra HTTP call, creates a false hit in the logs, and makes an assumption about how authorization is handled across the app.
There could be a secondary concern - the page might be authorized, but just change how it works or looks. This particular app has no change in look based on account (besides the account strip itself), and I can handle functionality changes by just providing a custom event that forms listen to - they can reload any relevant data from the server in response to it.
发布评论
评论(2)
仅当您仅使用 URL 授权时,才可以使用 UrlAuthorization.CheckUrlAccessForPrincipal。但对于使用路由的 MVC,我们强烈建议您不要使用 URL 授权来保护应用程序。
相反,我们建议在控制器类上使用授权属性。原因是可能有多个 URL 调用同一控制器操作。最好在资源处保护资源,而不仅仅是在入口处。
在这种特殊情况下,您必须获取给定 URL 的控制器实例。这有点棘手,因为您基本上必须从拥有 URL 的点到拥有控制器的点运行 MVC 管道。这是可能的,但看起来很重量级。
我想知道是否有更好、更简单的方法来实现您的目标。你真正想做什么?
更新:根据您的情况,听起来这只是出于 UI 目的的初始检查。也许您需要做的只是向 URL 发出异步 Ajax 请求并检查 HTTP 状态代码。如果是 401 状态代码,则表明用户未获得授权。这似乎是最安全的选择。
Using UrlAuthorization.CheckUrlAccessForPrincipal only works if you're only using URL authorization. But for MVC using Routing, we highly recommend that you don't use URL authorization to secure an app.
Instead, we recommend using Authorization attributes on the controller class. The reason is there could be multiple URLs that call the same controller action. It's always better to secure the resource at the the resource and not just at the entry ways.
In this particular case, you'd have to get an instance of the controller given the URL. THat's a little tricky as you'll basically have to run the MVC pipeline from the point where you have the URL to the point where you have the controller. It's possible, but seems heavyweight.
I wonder if there isn't a better and simpler way to accomplish your goals. What is it you're really trying to do?
UPDATE: Based on your scenario, it sounds like this is an initial check just for UI purposes. Perhaps all you need to do is make an asynchronous Ajax request to the URL and check the HTTP Status code. If it's a 401 status code, you know the user is not authorized. That seems like the safest bet.
UrlAuthorizationModule.CheckUrlAccessForPrincipal 方法怎么样。
UrlAuthorizationModule.CheckUrlAccessForPrincipal 方法 (System.Web.Security)
How about UrlAuthorizationModule.CheckUrlAccessForPrincipal method.
UrlAuthorizationModule.CheckUrlAccessForPrincipal Method (System.Web.Security)