1

フォーム認証を使用する LightSwitch 2011 Web アプリケーションで問題が発生しました。

Active Directory に対してユーザーを認証する独自のログイン画面を実装しました。私のコードでは、ユーザーが特定の Active Directory グループに割り当てられているかどうかもチェックして、データを追加/編集/削除できるかどうかを判断します。

ログイン フォームは、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"]);
}

たとえば、CanExcecute1 つのテーブルのメソッド

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();
}

WebConfig

<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()。セッション トークンisUserAdminNULL?! セッション トークンはlogin.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。探しているリソース (またはその依存関係の 1 つ) は、削除されたか、名前が変更されたか、一時的に利用できない可能性があります。次の URL を見直して、スペルが正しいことを確認してください。

要求された URL: /LogOff.aspx

修正はこれです:

まず、ソリューション エクスプローラーでプロジェクト名を右クリックし、プロジェクトをアンロードします。プロジェクトがアンロードされたら、プロジェクトを右クリックして project_name.lsproj を編集します。Ctrl+Fのためにdefault.htm。によって進められているセクションを探しています_BuildFile_BuildFileそのセクションを からにコピーし、そのセクションの/_BuildFile下に貼り付けて、次のように変更します。

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

右クリックしてプロジェクトをリロードします。ビルドしようとしたときにエラーが発生した場合は、ビルド | を試してください。クリーンアップして再度ビルドします。アプリケーションをデバッグで実行すると、このコードはページをリロードするだけです。ただし、公開した後にコードが原因isUserAdminになるとNULL、ログアウトしてログオン画面に戻る必要があります。

参考文献:

元の MSDN フォーラム スレッド

私の実装経験

于 2012-08-13T12:57:42.783 に答える