9

我们有一个 ASP.NET MVC 4 Intranet 应用程序。我们正在使用 Windows 身份验证,这方面工作正常。使用用户的凭据,我们可以从 Web 应用程序访问这些凭据。

然而,我们真正想要的是某种混合模式。我们想从浏览器中获取用户的凭据,但我们也想验证用户是否在我们应用程序的数据库中。如果用户在数据库中,那么他们可以继续。如果不是,我们希望将它们重定向到要求备用凭据的页面。我现在正在做的是,在Global.asax.cs,我有一个Application_AuthenticateRequest方法,我正在检查用户是否经过身份验证。如果他们是并且他们的 cookie 信息不能反映他们已登录系统的事实,那么我将他们登录并设置一些包含用户信息的 cookie。如果他们没有通过身份验证,我会将他们重定向到登录页面。由于公司政策涉及的原因,我们不能使用 AD 角色,因此我们需要使用数据库进行额外的身份验证。

我猜Application_AuthenticateRequest不是这样做的地方,但也许是。但是我们基本上需要一个地方来过滤身份验证请求。但另外这个实现让我遇到了另一个问题:

我们的应用中有某些 URL 允许匿名访问。我已经<location>为这些添加了标签到 web.config。问题是,当对这些进行匿名调用时,它会Application_AuthenticateRequest尝试将用户登录到数据库中。现在,我可以添加代码Application_AuthenticateRequest来处理这些 URL,这是我目前的计划,但如果我正在编写并且Application_AuthenticateRequest不是这样做的地方,那么我宁愿现在解决而不是以后解决。

4

1 回答 1

5

为此,您需要使用操作过滤器。您可以像这样扩展 AuthorizeAttribute:

public class MyAuthorizeAttribute : AuthorizeAttribute
{
    private UnitOfWork _unitOfWork = new UnitOfWork();

    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        var isAuthorized = false;
        var username = httpContext.User.Identity.Name;
        // Some code to find the user in the database...
        var user = _unitOfWork.UserRepository.Find(username);
        if(user != null)
        {
           isAuthorized = true;
        }


        return isAuthorized;
    }

    public override void OnAuthorization(AuthorizationContext filterContext)
    {            
        if (filterContext == null)
        {
            throw new ArgumentNullException("filterContext");
        }

        if (AuthorizeCore(filterContext.HttpContext))
        {
            SetCachePolicy(filterContext);
        }
        else
        {
           // If not authorized, redirect to the Login action 
           // of the Account controller... 
          filterContext.Result = new RedirectToRouteResult(
            new System.Web.Routing.RouteValueDictionary {
               {"controller", "Account"}, {"action", "Login"}
            }
          );               
        }
    }

    protected void SetCachePolicy(AuthorizationContext filterContext)
    {
        // ** IMPORTANT **
        // Since we're performing authorization at the action level, 
        // the authorization code runs after the output caching module. 
        // In the worst case this could allow an authorized user 
        // to cause the page to be cached, then an unauthorized user would later 
        // be served the cached page. We work around this by telling proxies not to 
        // cache the sensitive page, then we hook our custom authorization code into 
        // the caching mechanism so that we have the final say on whether a page 
        // should be served from the cache.
        HttpCachePolicyBase cachePolicy = filterContext.HttpContext.Response.Cache;
        cachePolicy.SetProxyMaxAge(new TimeSpan(0));
        cachePolicy.AddValidationCallback(CacheValidationHandler, null /* data */);
    }

    public void CacheValidationHandler(HttpContext context,
                                        object data,
                                        ref HttpValidationStatus validationStatus)
    {
        validationStatus = OnCacheAuthorization(new HttpContextWrapper(context));
    }
}

然后,您可以在 Controller 级别或 Action 级别使用此属性,如下所示:

[MyAuthorize]
public ActionResult SomeAction()
{
  // Code that is supposed to be accessed by authorized users only
}
于 2013-07-03T19:21:58.750 回答