ASP.NET LoginStatus コントロール - 生成された QueryString の ReturnURL をオーバーライドする
-
05-07-2019 - |
質問
を使用しているウェブサイトがあります ASP.NET ログイン コントロール そしてフォーム認証。サイトのヘッダー部分の表示を管理する別の Web ユーザー コントロール内に asp:LoginStatus コントロールを配置しました。
私が抱えている問題は、LoginStatus コントロールによって提示される ReturnURL が、ユーザーが現在いるページではなく、Header Control へのパスを参照していることです。これはおそらくクラス階層と、ヘッダー コントロール (ascx) が実際に .aspx ファイルの Server.Execute を使用して HTML を生成していることが原因です。これは、ページ上に複数のサーバー側フォームを配置できないという問題を回避するための回避策です。
したがって、ページの実際のクラス階層は次のようになります。
Default.aspx - Uses Page.Master
Page.Master includes <foo:Header>
(with a reference to "~/Controls/Components/Header.ascx")
Header.ascx simply includes an <asp:Literal>
on Page_Load performs a Server.Execute ("~/Controls/Pages/Header.aspx")
and writes the content out to the Literal
Header.aspx includes <asp:LoginStatus>
ユーザーがログイン リンクをクリックすると、Login.aspx に正しくリダイレクトされますが、表示される ReturnURL は (間違っています - 理由は理解できますが) "ReturnUrl=%2fControls%2fPages%2fHeader.aspx"
.
ログイン ページにアクセスすると、LoggedIn イベントを問題なく処理して、ユーザーを適切な場所に正しくリダイレクトできます。私がやりたいことは次のいずれかです:1)クエリ文字列から完全にreturnurlを削除する2)LogginstatusコントロールがレンダリングされたときにReturnurlを制御できるようにします。
System.Web.UI.WebControls.LoginStatus のリフレクタ処理をいくつか行ったところ、次のコードに基づいて、常に ReturnURL を使用するようにハードコーディングされているようです。
private string NavigateUrl
{
get
{
if (!base.DesignMode)
{
return FormsAuthentication.GetLoginPage(null, true);
}
return "url";
}
}
これは常に、reuseReturnURL を true に設定します。
おそらく、唯一の選択肢は、独自の LoginStatus コントロールをロールすることなのでしょうか?
[編集:もともと簡潔にするために、以下の詳細を省略しました]
これは私が達成しようとしていることの非常に単純な例です:
Web アプリケーション プロジェクトは次の構造になっています。ウェブサイト - コントロール - コンポーネント-Footer.Ascx -header.Ascx -MasterPages -site.master -default.aspx -login.aspx
興味があればページのマークアップを以下に示します。
懸念事項を分離するために Web ユーザー コントロールを作成しましたが、ログイン ページで asp:Login コントロールを使用するには、(サーバー側) フォームにネストする必要があります。asp:LoginStatus コントロールも (サーバー側) フォームにネストする必要があります。ページ上に複数のサーバー側フォームを含めることはできないため、これは問題になります。
また、その答えは、ログイン ページで LoginStatus コントロールを抑制するだけではありません。メイン ページに小さな検索コントロールを追加したいだけで、これも (サーバー側の) フォームに依存することになると想像してください。これが、Server.Execute を使用し、ASPX からページを生成する理由です。これにより、.NET が「騙されて」、ページ上で複数のサーバー側フォームが許可されるようになります。(どうやってかは聞かないでください...わからない!)
私のアーキテクチャ設計全体が間違っているのかもしれませんが、他の人はサーバー側のフォームを必要とするページ上に複数の Web ユーザー コントロールをどのように配置するのでしょうか?それともそうではありませんか?
Site.Master マークアップ:
<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="Site.master.cs" Inherits="WebSite.MasterPages.Site" %>
<%@ Register TagPrefix="bs" TagName="Footer" Src="~/Controls/Components/Footer.ascx" %>
<%@ Register TagPrefix="bs" TagName="Header" Src="~/Controls/Components/Header.ascx" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title></title>
<asp:ContentPlaceHolder ID="head" runat="server">
</asp:ContentPlaceHolder>
</head>
<body id="Body" runat="server">
<div id="container">
<!-- start header -->
<bs:Header ID="Header" runat="server" />
<!-- end header -->
<div id="central">
<div id="main">
<asp:PlaceHolder ID="MainContentPlaceHolder" runat="server">
<!-- start main content -->
<div>
<asp:ContentPlaceHolder ID="MainContent" runat="server" />
</div>
<!-- end main content -->
</asp:PlaceHolder>
</div>
</div>
<!-- start footer -->
<bs:Footer ID="Footer" runat="server" />
<!-- end footer -->
</div>
</body>
</html>
Default.aspx マークアップ:
<%@ Page MasterPageFile="~/MasterPages/Site.Master" Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="WebSite._Default" %>
<asp:Content ID="Content1" runat="server" ContentPlaceHolderID="MainContent">
Main Body Content <br />
<br />
</asp:Content>
Header.ascx マークアップ:
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="Header.ascx.cs" Inherits="WebSite.Controls.Components.Header" %>
<div id="header">
Header Content <br />
<div id="loginstatus">
<form id="Form1" runat="server">
<asp:LoginView ID="displayloginname" runat="server">
<AnonymousTemplate>
<a href="../../Registration.aspx">Register</a>
</AnonymousTemplate>
<LoggedInTemplate>
Welcome
<asp:LoginName runat="server" ID="ctlLoginName" />
</LoggedInTemplate>
</asp:LoginView>
<asp:LoginStatus ID="displayloginstatus" runat="server" LoginText="Login" LogoutPageUrl="~/Default.aspx"
LogoutAction="Redirect" />
</form>
<br />
</div>
</div>
Footer.ascx マークアップ:
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="Footer.ascx.cs" Inherits="Website.Controls.Components.Footer" %>
<div id="footer">
Footer Content
<ul class="links">
<asp:PlaceHolder ID="ListItems" Runat="server">
<li><a runat="server" id="HomeLink" href="~/">Home</a></li>
<li><a runat="server" href="~/" ID="A1">About Us</a></li>
<li><a id="A2" runat="server" href="~/">Contact Us</a></li>
<li><a id="A3" runat="server" href="~/">Privacy Policy</a></li>
<li><a id="A4" runat="server" href="~/">Accessibility Policy</a></li>
<li><a id="A5" runat="server" href="~/">Legal Notices</a></li>
<li><a id="A6" runat="server" href="~/">Sitemap</a></li>
<li><a id="A7" runat="server" href="~/">RSS Feeds</a></li>
</asp:PlaceHolder>
</ul>
</div>
Login.aspx マークアップ:
<%@ Page MasterPageFile="~/MasterPages/Site.Master" Language="C#" AutoEventWireup="true" CodeBehind="Login.aspx.cs" Inherits="Website.Login" %>
<asp:Content ID="Content1" runat="server" ContentPlaceHolderID="MainContent">
Main Body Content <br />
<br />
<form id="form1" runat="server">
<div>
<asp:Login ID="Login1" runat="server">
</asp:Login>
</div>
</form>
</asp:Content>
解決
2 つのオプションが表示されます。
- フォームタグをマスターページに配置します。すぐ下に
<div id="container"
> そしてすべてのコンテンツをその div でラップします。 - ASP.NET フォームを必要としないようにヘッダーを変更します。LoginView または LoginStatus の両方に ASP.NET フォームが必要かどうかはわかりません。その後、マスター ページを使用する aspx ファイルのフォーム タグを残しておくことができます (Login.aspx と同様)。これは、フォーム タグを (マスター ファイルではなく) aspx ページにのみ配置し、ヘッダーとフッターに ASP.NET フォームが必要ないことを確認することです (runat=server を使用しないだけで、通常のフォーム タグを使用できます)。
他のヒント
Header.ascx から Header.aspx の Server.Execute を実行するのはなぜですか?Header.aspx コードを Header.ascx に入れてみてはいかがでしょうか。そうすれば、ReturnUrl は期待どおりのページになります。
ここで何かが正しく聞こえません:
Page_Load で Server.Execute("~/Controls/Pages/Header.aspx") を実行します。
そしてコンテンツをリテラルに書き込みます
なぜこんなことをするのか理解できませんか?ASP.NET がページ上で複数の HtmlForm を許可しないという問題を回避しようとしているためだと述べています。しかし、header.aspx の HTML コンテンツをリテラルに挿入しているだけの場合、HtmlForm は使用していません。それでは、Header.aspx の内容を通常の形式のタグ (runat=server なし) に置くことはできますか?それとも、ログイン ステータス コントロールを完全にフォームの外に置くことができますか?そもそも、Header.aspx のコンテンツには本当にフォームが必要なのでしょうか?
私なら、なぜ header.aspx ページの内容をリテラルに書き出すのかをよく調べて、LoginStatus コントロールに飛び込み、意図されていないことを行うように変更するのではなく、そこで問題を修正してみます。
もう 1 つの考えられる提案:Header をリテラルにロードする必要がある場合、代わりに Page.LoadUserControl を使用できますか?これにより、URL が自動的に解決される可能性がありますか?ただし、100%確実ではありません。