Application_AuthenticateRequest一直在调用无限重定向

时间:2012-06-03 08:47:03

标签: c# asp.net form-authentication

这是我previous question here的延续。

我曾尝试使用内置的ASP登录机制,但它对我不起作用。主要原因是,我被要求保持简单明了。

现在,我站在这里:

的Web.config

<system.web>
    <sessionState timeout="10" />

    <authentication mode="Forms">
        <forms timeout="30" loginUrl="~/SecuredArea/LogInOut/log-in.aspx" />
    </authentication>

    <authorization>
        <allow users="?" />
    </authorization>

</system.web>

<location path="SecuredArea/AdminArea">
    <system.web>
        <authorization>
            <allow roles="administrators" />
            <deny users="*" />
        </authorization>
    </system.web>
</location>

<location path="SecuredArea/EmployeeArea">
    <system.web>
        <authorization>
            <allow roles="employees" />
            <deny users="*" />
        </authorization>
    </system.web>
</location>

Global.asax中

protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
    if (HttpContext.Current.User != null)
    {
        if (HttpContext.Current.User.Identity.IsAuthenticated)
        {
            IIdentity userId = HttpContext.Current.User.Identity;

            //if role info is already NOT loaded into cache, put the role info in cache
            //if (HttpContext.Current.Cache[userId.Name] == null)
            //{
            //  string[] roles;

            //  if (userId.Name == "admin")
            //  {
            //    roles = new string[1] { "administrators" };
            //  }
            //  else if (userId.Name == "member1")
            //  {
            //    roles = new string[1] { "employees" };
            //  }
            //  else
            //  {
            //    roles = new string[1] { "public" };
            //  }

              //1 hour sliding expiring time. Adding the roles in cache. 
              //This will be used in Application_AuthenticateRequest event located in Global.ascx.cs 
              //file to attach user Principal object.
            //  HttpContext.Current.Cache.Add(userId.Name, roles, null, DateTime.MaxValue, TimeSpan.FromHours(1), CacheItemPriority.BelowNormal, null);
            //}

            //now assign the user role in the current security context
            HttpContext.Current.User = new GenericPrincipal(userId, (string[])HttpContext.Current.Cache[userId.Name]);
        }
    }
}

我在这里评论了令人困惑的代码,因为我不想访问数据库并在这里遍历所有可能的员工。对于管理员帐户,这很容易,但对于员工帐户,这是不可能的。

登录in.aspx.cs

protected void ButtonLogOn_Click(object sender, EventArgs e)
{
    if (String.IsNullOrEmpty(txtUserName.Value.Trim()) || String.IsNullOrEmpty(txtPassword.Value.Trim()))
    {
        labelMessage.Text = MessageFormatter.GetFormattedErrorMessage("You can login using a username and a password associated with your account. Make sure that it is typed correctly.");
    }
    else
    {
        try
        {
            LoginPage loginBack = new LoginPage();
            int result = loginBack.VerifyCredentials(txtUserName.Value.Trim(), txtPassword.Value.Trim());

            switch (result)
            {
                case -9:
                //System needs provisioning
                labelMessage.Text = MessageFormatter.GetFormattedErrorMessage("SMB Password Reset System need provisioning. Login as Administrator.");
                break;

                case 0:
                //Enroll-able User
                // Success, create non-persistent authentication cookie.
                FormsAuthentication.SetAuthCookie(txtUserName.Value.Trim(), false);

                FormsAuthenticationTicket ticketEmployee =
                    new FormsAuthenticationTicket(
                        1,                                                      // version
                        txtUserName.Value.Trim(),           // get username  from the form
                        DateTime.Now,                                   // issue time is now
                        DateTime.Now.AddMinutes(10),    // expires in 10 minutes
                        false,                                              // cookie is not persistent
                        "employees");

                HttpCookie cookieEmployee = new HttpCookie(FormsAuthentication.FormsCookieName, FormsAuthentication.Encrypt(ticketEmployee));
                Response.Cookies.Add(cookieEmployee);

                SiteLogin.PerformAuthentication(txtUserName.Value.Trim(), false);
                break;

                case 1:
                //User not in required directory group
                labelMessage.Text = MessageFormatter.GetFormattedErrorMessage("You cannot login because you are not authorized.");
                break;

                default:
                //Bad name and/or password                              
                labelMessage.Text = MessageFormatter.GetFormattedErrorMessage("You can login using a username and a password associated with your account. Make sure that it is typed correctly.");
                break;
            }
        }
        catch (MessageSecurityException expMse)
        {
            //Bad name and/or password
            Debug.WriteLine("Error: " + expMse.Message);
            labelMessage.Text = MessageFormatter.GetFormattedErrorMessage("You can login using a username and a password associated with your account. Make sure that it is typed correctly.");
        }
        catch (Exception exp)
        {
            labelMessage.Text = MessageFormatter.GetFormattedErrorMessage("Some general error has occured. Message reads: " + exp.Message);
        }
    }
}

protected void ButtonAdminLogOn_Click(object sender, EventArgs e)
{
    if (String.IsNullOrEmpty(txtUserName.Value) || String.IsNullOrEmpty(txtPassword.Value))
        labelMessage.Text = MessageFormatter.GetFormattedErrorMessage("<strong>Login Please!</strong><hr/>You can login using a username and a password associated with your account. Make sure that it is typed correctly.");
    else
    {
        //if the log-in is successful
        if (txtUserName.Value == "admin" && txtPassword.Value == "AlphaBeta")
        {
            // Success, create non-persistent authentication cookie.
            FormsAuthentication.SetAuthCookie(txtUserName.Value.Trim(), false);

            FormsAuthenticationTicket ticketAdmin =
                new FormsAuthenticationTicket(
                    1,                                                      // version
                    txtUserName.Value.Trim(),           // get username  from the form
                    DateTime.Now,                                   // issue time is now
                    DateTime.Now.AddMinutes(10),    // expires in 10 minutes
                    false,                                              // cookie is not persistent
                    "administrators");

            HttpCookie cookieAdmin = new HttpCookie(FormsAuthentication.FormsCookieName, FormsAuthentication.Encrypt(ticketAdmin));
            Response.Cookies.Add(cookieAdmin);

            SiteLogin.PerformAdminAuthentication(txtUserName.Value.Trim(), false);
        }
        else
        {
            labelMessage.Text = MessageFormatter.GetFormattedErrorMessage("<strong>Login Failed!</strong><hr/>The username and/or password you entered do not belong to any Administrator account on our system.<br/>You can login using a username and a password associated with your account. Make sure that it is typed correctly.");
        }
    }
}

最后,实用程序类: SiteLogin.cs

public sealed class SiteLogin
{       
    public static void PerformAuthentication(string userName, bool remember)
    {
        FormsAuthentication.RedirectFromLoginPage(userName, remember);

        if (HttpContext.Current.Request.QueryString["ReturnUrl"] == null)
        {
            RedirectToDefaultPage();
        }
        else
        {
            HttpContext.Current.Response.Redirect(HttpContext.Current.Request.QueryString["ReturnUrl"]);
        }
    }

    public static void PerformAdminAuthentication(string userName, bool remember)
    {
        FormsAuthentication.RedirectFromLoginPage(userName, remember);

        if (HttpContext.Current.Request.QueryString["ReturnUrl"] == null)
        {
            RedirectToAdminDefaultPage();
        }
        else
        {
            HttpContext.Current.Response.Redirect(HttpContext.Current.Request.QueryString["ReturnUrl"]);
        }
    }

    /// <summary>
    /// Redirects the current user based on role
    /// </summary>
    public static void RedirectToDefaultPage()
    {
        HttpContext.Current.Response.Redirect("~/SecuredArea/EmployeeArea/EmployeeDefaultPage.aspx");
    }

    /// <summary>
    /// Redirects the current user based on role
    /// </summary>
    public static void RedirectToAdminDefaultPage()
    {
        HttpContext.Current.Response.Redirect("~/SecuredArea/AdminArea/AdminDefaultPage.aspx");
    }

    public static void LogOff()
    {
        // Put user code to initialize the page here
        FormsAuthentication.SignOut();

        //// Invalidate roles token
        //Response.Cookies[Globals.UserRoles].Value = "";
        //Response.Cookies[Globals.UserRoles].Path = "/";
        //Response.Cookies[Globals.UserRoles].Expires = new System.DateTime(1999, 10, 12);

        //Set the current user as null
        HttpContext.Current.User = null;
    }
}

现在,每当我尝试登录时,我都会遇到严重不一致的行为。最大的问题是,一旦我尝试访问Admin或Employee的任何受保护页面,我就会被重定向到Login页面。我提供了详细信息并尝试登录并在两者(简单的管理员登录和复杂的员工登录)案例中,我在浏览器中收到错误。 IE没有多大意义,但Firefox抱怨有些道理:

  

页面未正确重定向    Pale Moon已检测到服务器正在以永远无法完成的方式重定向此地址的请求。   有时可能会因禁用或拒绝接受Cookie而导致此问题。

我在调试时遇到了不好的时间,但似乎是Global.asax的{​​{1}}方法中的一个方法,该方法只是一遍又一遍地调用。

有趣的是,如果我进入未受保护的页面,我可以看到自己登录并在我的标题中获得“欢迎管理!,注销”。这是通过母版页

动态完成的
Application_AuthenticateRequest()

任何人都可以识别出这个问题吗?我今天真的需要关闭这件事。感谢。

修改

我使用过fiddler,我看到一旦按下登录,就会创建一个无限循环。我可以通过图像显示行为:

访问安全区域时登录页面

Thrown to login page upon accessing a secured area

输入凭据并按下登录按钮

Entered the credentials and pressed the login button

接受凭据并将其重定向回安全页面并重新定向到登录等等

Credentials accepted and redirected back to secure page and redirected again to login and so forth

我选择了fiddler的Cookies标签,因为那里检测到了明显的变化。

0 个答案:

没有答案