1

我遇到了使用表单身份验证的 LightSwitch 2011 Web 应用程序的问题。

我已经实现了我自己的登录屏幕,它根据活动目录对用户进行身份验证。我的代码还检查用户是否被分配到特定的活动目录组,以决定他们是否可以添加/编辑/删除数据。

登录表单放置在 Login.aspx 页面上。登录按钮包含以下代码:

protected void buttonLogin_Click(object sender, EventArgs e)
{
    LdapAuthentication authentication = new LdapAuthentication();

    try
    {
        bool isUserAdmin = false;
        if (authentication.IsUserAuthenticated(textBoxUserName.Text, textBoxPassword.Text, ref isUserAdmin))
        {
            FormsAuthenticationTicket authenticationTicket = new FormsAuthenticationTicket(1,
            textBoxUserName.Text, DateTime.Now, DateTime.Now.AddSeconds(1), false, String.Empty);

            //Encrypt the ticket.
            string encryptedTicket = FormsAuthentication.Encrypt(authenticationTicket);

            //Create a cookie, and then add the encrypted ticket to the cookie as data.
            HttpCookie authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);

            //Add the cookie to the outgoing cookies collection.
            Response.Cookies.Add(authCookie);

            //If the everyoneAdmin is set to true the validation of the administratorgroup
            //is decativated so we have to grant the current user administrator rights
            if (everyoneAdmin)
                isUserAdmin = true;

            Session["isUserAdmin"] = isUserAdmin ;

            Response.Redirect("default.htm");
        }
    }
    catch (Exception ex)
    {
        labelError.Text = ex.Message;
        labelError.Visible = true;
        textBoxPassword.Text = String.Empty;
    }
}

public bool IsUserAuthenticated(String userName, String password, ref bool isUserAdmin)
{
    if (String.IsNullOrEmpty(userName) || String.IsNullOrEmpty(password))
        return false;

    String domain = String.Empty;
    if (!String.IsNullOrEmpty(ConfigurationManager.AppSettings["Domain"]))
        domain = Convert.ToString(ConfigurationManager.AppSettings["Domain"]).Trim();
    else
        throw new NullReferenceException("The Domain in the configuration must not be null!");

    String ldpa = String.Empty;
    if (!String.IsNullOrEmpty(ConfigurationManager.AppSettings["LDPA"]))
        ldpa = String.Format("LDAP://{0}", Convert.ToString(ConfigurationManager.AppSettings["LDPA"]).Trim());
    else
        throw new NullReferenceException("The LDPA in the configuration must not be null!");

    String administrationGroup = String.Empty;
    if (!String.IsNullOrEmpty(ConfigurationManager.AppSettings["AdministratorGroup"]))
        administrationGroup = Convert.ToString(ConfigurationManager.AppSettings["AdministratorGroup"]).Trim();
    else
        throw new NullReferenceException("The AdministrationGroup in the configuration must not be null!");

    String domainUserName = String.Format(@"{0}\{1}", domain.Trim(), userName.Trim());
    DirectoryEntry directoryEntry = new DirectoryEntry(ldpa, domainUserName, password);

    try
    {
        //Bind to the native AdsObject to force authentication.
        object obj = directoryEntry.NativeObject;
        DirectorySearcher directorySearcher = new DirectorySearcher(directoryEntry);

        directorySearcher.Filter = String.Format("(SAMAccountName={0})", userName.Trim());
        directorySearcher.PropertiesToLoad.Add("cn");
        directorySearcher.PropertiesToLoad.Add("memberOf");
        SearchResult directorySearchResult = directorySearcher.FindOne();

        //unable to find a user with the provided data
        if (directorySearchResult == null)
            return false;

        if (directorySearchResult.Properties["memberof"] != null)
        {
            //If the memberof string contains the specified admin group
            for (int i = 0; i < directorySearchResult.Properties["memberof"].Count; i++)
            {
                string temp = directorySearchResult.Properties["memberof"].ToString();
                // get the group name, for example:
                if (directorySearchResult.Properties["memberof"].ToString().ToLower().Contains(administrationGroup.ToLower()))
                {
                    isUserAdmin = true;
                    break;
                }
            }
        }
    }
    catch (Exception ex)
    {
        throw new Exception(String.Format("Error authenticating user.\n\rMessage:\n\r {0}", ex.Message));
    }

    return true;
}

在包含CanExcecute(服务器层)方法的类中,我实现了以下方法:

public bool IsCurrentUserAdmin()
{
    if (HttpContext.Current.Session["isUserAdmin"] == null)
        return false;

    return (bool)(HttpContext.Current.Session["isUserAdmin"]);
}

例如,CanExcecute一张表的方法

partial void dtFacilities_CanDelete(ref bool result)
{
    result = this.IsCurrentUserAdmin();
}

partial void dtFacilities_CanInsert(ref bool result)
{
    result = this.IsCurrentUserAdmin();
}

partial void dtFacilities_CanUpdate(ref bool result)
{
    result = this.IsCurrentUserAdmin();
}

网络配置

<authentication mode="Forms">
  <form>s name=".ASPXAUTH"
       loginUrl="Login.aspx"
       protection="All"
       timeout="30"
       path="/"
       requireSSL="false"
       slidingExpiration="true"
       defaultUrl="Home.aspx"
       cookieless="UseUri" />
</authentication>
<authorization>
  <deny users="?">
</deny></authorization>

问题

  1. 问题是,如果用户空闲时间超过timeout会话超时。所以,会话令牌isUserAdminNULL. 此时我希望应用程序返回登录屏幕。AResponse.Redirect和 a在该方法Server.Transfer中不起作用。如果会话令牌是IsCurrentUserAdmin(),我如何让应用程序将用户返回到登录屏幕?!请记住,会话令牌是在后面的页面代码中设置的isUserAdminNULLlogin.aspx

  2. 当用户关闭 Lightswitch 应用程序的最后一个选项卡时,应用程序会打开一个新选项卡并导航到登录页面,他们会自动登录,而无需处理页面上的登录过程login.aspx。这意味着会话令牌isUserAdminNULL. 即使用户在关闭应用程序的最后一个选项卡之前没有登录,也会发生这种情况。这再次导致问题 1。

提前致谢!

4

1 回答 1

0

如果我正确理解您的问题,如果出于某种原因isUserAdmin设置为NULL,则您希望将用户返回到登录屏幕。

在我的应用程序中,我只需使用一个用户可以单击以注销的按钮。但在你的情况下,底层方法应该是一样的。

首先创建一个名为 LogOff.aspx 的新页面。页面本身,您可以保留默认生成的代码:

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>

    </div>
    </form>
</body>
</html>

对于后面的代码,你会想要这样的东西(请检查这个,我从我在 VB 中的项目转换而来):

using System.Web.Security;

namespace LightSwitchApplication
{
  public partial class LogOff : System.Web.UI.Page
  {
    protected void Page_Load(object sender, EventArgs e)
    {
      FormsAuthentication.SignOut();
      Response.Redirect("default.htm");
    }
  }
}

这是我使用按钮的代码。但是,如果您将Dispatcher调用部分Navigate放在您的IsCurrentUserAdmin()方法中,它应该执行相同的技巧(再次检查 C#):

using Microsoft.LightSwitch.Threading;
using System.Windows.Browser;

        partial void btnLogOff_Execute()
        {
            Dispatchers.Main.Invoke(() =>
            {
                HtmlPage.Window.Navigate(new Uri("LogOff.aspx", UriKind.Relative));
            });
        }

根据我的经验,Lightswitch 中存在一些问题。如果您按原样执行,您可能会收到以下信息:

“/”应用程序中的服务器错误。

无法找到该资源。

说明: HTTP 404。您要查找的资源(或其依赖项之一)可能已被删除、名称已更改或暂时不可用。请查看以下 URL 并确保其拼写正确。

请求的 URL: /LogOff.aspx

修复是这样的:

首先在解决方案资源管理器中右键单击您的项目名称并卸载项目。卸载项目后,右键单击它并编辑 project_name.lsproj。Ctrl+Fdefault.htm. 您正在寻找由_BuildFile. 将该部分从 复制_BuildFile/_BuildFile,粘贴到该部分下方并进行如下修改。

<_BuildFile Include="Server/LogOff.aspx">
  <SubFolder>
  </SubFolder>
  <PublishType>
  </PublishType>
</_BuildFile>

现在右键单击并重新加载您的项目。如果您在尝试构建时遇到错误,请尝试构建 | 清理并重新构建。如果您在 Debug 中运行应用程序,此代码只会重新加载页面。但是,一旦您发布并随后导致isUserAdmin成为NULL代码,您应该退出并带您回到登录屏幕。

参考:

原始 MSDN 论坛主题

我实施它的经验

于 2012-08-13T12:57:42.783 回答