Application_AuthenticateRequest продолжает вызывать бесконечные перенаправления

Это продолжение моего предыдущего вопроса здесь.

Я пытался использовать встроенный механизм входа в систему 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]);
        }
    }
}

Я прокомментировал запутанный код здесь, потому что я не хочу получать доступ к БД и перебирать здесь всех возможных сотрудников. Для учетной записи администратора это просто, а для учетной записи сотрудника это невозможно.

log-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;
    }
}

Теперь я получаю серьезно непоследовательное поведение всякий раз, когда пытаюсь войти в систему. Самая большая проблема заключается в том, что когда я пытаюсь получить доступ к любой из защищенных страниц для администратора или сотрудника, меня перенаправляют на страницу входа. Я предоставляю данные и пытаюсь войти в систему, и в обоих случаях (простой вход администратора и сложный вход сотрудника) я получаю сообщение об ошибке в браузере. IE не имел особого смысла, но жалобы Firefox имели смысл:

Страница перенаправляется неправильно Pale Moon обнаружила, что сервер перенаправляет запрос на этот адрес способом, который никогда не будет завершен. Иногда эта проблема может быть вызвана отключение или отказ от приема файлов cookie.

У меня проблемы с отладкой, но кажется, что внутри метода Global.asax Application_AuthenticateRequest() этот метод просто вызывается снова и снова.

Забавно, что если я захожу на незащищенные страницы, я вижу, что я вошел в систему, и получаю «Добро пожаловать, администратор!, Выход» в моем заголовке. Это делается динамически через мастер-страницу.

<div class="info-area">
    <asp:LoginView ID="HeadLoginView" runat="server" EnableViewState="false">
        <LoggedInTemplate>
            Welcome <span class="bold">
                <asp:LoginName ID="HeadLoginName" runat="server" />
            </span>! |
        </LoggedInTemplate>
    </asp:LoginView>
    <asp:LoginStatus ID="HeadLoginStatus" runat="server" LogoutAction="Redirect" LogoutText="Logout" LogoutPageUrl="~/SecuredArea/LogInOut/log-out.aspx" />
</div>

Кто-нибудь может определить проблему? Мне действительно нужно закрыть это дело сегодня. Спасибо.

ИЗМЕНИТЬ

Я использовал fiddler и вижу, что после входа в систему создается бесконечный цикл. Я могу показать поведение через изображения:

Перебрасывается на страницу входа при входе в защищенную зону

Перебрасывается на страницу входа при доступе к защищенной области

Ввел учетные данные и нажал кнопку входа

Введены учетные данные и нажата кнопка входа

Учетные данные приняты и перенаправлены обратно на защищенную страницу и снова перенаправлены на вход и т. д.

Учетные данные приняты и перенаправлены обратно на защищенную страницу и снова перенаправлены для входа в систему и т. д.

Я выбираю вкладку Cookies скрипача, потому что там было обнаружено явное изменение.


person Hassan Gulzar    schedule 03.06.2012    source источник
comment
На страницах SiteLogin и AdminLogin вы начинаете свои функции PerformAuthentication с FormsAuthentication.RedirectFromLoginPage(userName, помните); - это вызывает перенаправление обратно на страницу ReturnUrl, поэтому моя первая мысль будет заключаться в том, что вы посещаете страницу, перенаправляетесь на эту страницу входа, этот код затем перенаправляет вас обратно на первую страницу, и, поскольку вы еще не вошли in, он перенаправляет вас обратно сюда и так далее! Попробуйте для начала закомментировать эти строки, чтобы увидеть, не в этом ли проблема.   -  person dash    schedule 03.06.2012
comment
SiteLogin — это просто служебный класс для скрытия инструкций по перенаправлению. Дело в том, что внутри метода PerformAdminAuthentication() есть if-else. Я всегда попадаю в другую часть, что означает, что я не вошел в систему. Или это то, что я сделал вывод из Интернета.   -  person Hassan Gulzar    schedule 03.06.2012
comment
Согласитесь, но вы делаете RedirectFromLoginPage перед if-else, поэтому мне интересно, не это ли создает ваши проблемы с возвратом и отправкой.   -  person dash    schedule 03.06.2012