如何使用 ASP.NET MVC5 Windows 身份验证对首次登录执行一次性操作

How to perform one time action on first login using ASP.NET MVC5 Windows Authentication

我正在使用 ASP.NET MVC5 框架和 'windows authentication' 创建 Web 应用程序 - 即我正在创建一个 Intranet 应用程序,根据活动目录对用户进行身份验证。

当在公司的活动目录中定义新用户时,我需要捕获他的第一次登录并将他重定向到配置文件页面,提示用户填写一些信息。

如果用户在某些 table 中有自己的记录,我可以通过简单地查看数据库来捕获用户的首次登录。如果没有,用户是第一次来,我可以给他创建这样的记录。

交易来了 - 在广泛搜索各种可能性之后,似乎唯一的 "reasonable" 方法是通过自定义 AuthenticationFilter - 特别是将数据库检查逻辑放入

OnAuthenticationChallenge(AuthenticationChallengeContext filterContext)

方法。

我将 "reasonable" 放在引号中的原因是,一方面,这种方法符合 MVC 哲学——我的意思是它不是某种 'hack' 方法。

另一方面 - 因为我使用的是 windows 身份验证,所以实际上在任何控制器中都没有登录操作。用户可以输入任何 'www.mysite.com/controller/action' url,如果没有登录,则不会重定向到登录页面,windows 安全框只会出现提示输入凭据。这意味着我必须在全球范围内注册我的自定义身份验证过滤器以涵盖所有 controller/action 模式。这意味着将对每个请求执行数据库检查——我不喜欢这样。我不确定这会对性能造成多大影响,但从设计的角度来看它似乎也不正确。

我尝试的最后一件事是使用我的身份验证过滤器来捕获 'unauthenticated' 用户并将他们重定向到某些 'Login' 操作 - 但在这里我发现 windows 安全框甚至在身份验证过滤器被触发之前就出现了,所以从技术上讲,我的自定义身份验证过滤器永远不会捕获未经身​​份验证的用户。

所以我的问题是 - 是否有更好的方法如何通过一次性操作进入日志记录过程?或者我可以使用我拥有的 - 即全局注册的身份验证过滤器执行数据库检查每个请求?

谢谢

我相信这就是您要找的。此时您的数据库检查只会发生一次。您可以像这样将此方法添加到您的 Global.asax 中,一旦授权,它就可以与 Windows Auth 一起使用...

protected void Application_AuthorizeRequest(object sender, EventArgs e)
{
    // Do your check here
    // Do something
}

我终于有了一些可行的解决方案。

问题:

MVC5 APS.NET Intranet 应用程序使用 windows 身份验证。成功登录 active directory 后,我们想知道用户是否是第一次来到这里,如果是,则在应用程序数据库中创建他的记录。

解决方法:

因为我最终只对经过身份验证和授权的用户感兴趣,所以我创建了一个全局注册的操作过滤器,即过滤器将应用于每个controller/action组合成功后authentication/authorization.

在此过滤器中,我正在检查当前 session 标志 IsNewSession 是否设置为 true。如果是这样,我将对应用程序数据库执行该检查。这样即使每个请求都调用了操作过滤器,我也只在数据库中往返一次——在用户的第一个请求期间。

实施:

public class DbCheckFilter : ActionFilterAttribute
{
    private AppDbContext db = new AppDbContext();

    //we are overriding OnActionExecuting method since this one
    //is executed prior the controller action method itself
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        //is this a new session
        if (filterContext.HttpContext.Session.IsNewSession)
        {
            //we are storing users in db based on their active directory
            //Guid - therefore we need to get 'UserPrincipal' object
            //instead of 'WindowsPrincipal' provided by filterContext
            using (var principalContext = new PrincipalContext(ContextType.Domain))
            {
                var principal = UserPrincipal.FindByIdentity(principalContext, filterContext.HttpContext.User.Identity.Name);

                if (principal != null)
                {
                    //finally we perform the DB check itself
                    if (!CreateUserInDbIfNew(principal.Guid.Value, principal.DisplayName))
                    {
                        filterContext.Result = new HttpUnauthorizedResult();
                    }
                }
                else
                {
                    filterContext.Result = new HttpUnauthorizedResult();
                }
            }
        }

        base.OnActionExecuting(filterContext);
    }