زيادة مهلة جلسة العمل لتطبيقات ASP.NET Core التي تعمل على IIS

تحديث الصفحة :
تاريخ إنشاء الصفحة :

بيئة التحقق من العملية

فيجوال ستوديو
  • فيجوال ستوديو 2022
ASP.NET الأساسية
  • 8 (صفحات الحلاقة ، MVC)
خادم ويندوز
  • 2022
IIS
  • 10.0

بيئة التشغيل

لم نختبره في جميع الحالات ، ولكن يجب أن يعمل بشكل عام في ظل الظروف التالية:

فيجوال ستوديو
  • أي شيء يمكن أن يطور مشروعا أساسيا ASP.NET
ASP.NET الأساسية
  • أي إصدار (MVC ، صفحات الحلاقة ، API)
خادم ويندوز
  • ويندوز سيرفر 2008 أو أحدث
IIS
  • 7.0 أو أحدث

في البداية

تعمل التطبيقات المكتوبة باستخدام ASP.NET Core على خادم بسيط يسمى "Kestrel" ، ويتم تعيين المدة مثل مهلة الجلسة بشكل أساسي برمجيا.

ومع ذلك، إذا كنت تستضيف على IIS وتشغيل تطبيق ASP.NET الأساسية، قد تحتاج إلى تجاوز القيمة التي تم تعيينها في IIS عبر الإعداد البرمجي.

تتأثر مهلة جلسة العمل بسبب وقت الخمول الموضح هذه المرة بإعدادات IIS ، لذلك دعونا نقوم بتعيين هذه الإعدادات. ومع ذلك ، يرجى ملاحظة أن وقت الجلسة يتأثر بإعدادات متعددة ، لذلك اعتمادا على الإعداد ، قد لا يتم تمديد مهلة الجلسة بهذا الإعداد وحده.

يتم شرح ذلك من خلال برنامج اختبار ، ولكن إذا كنت تريد طريقة سريعة لإعداده ، فيرجى التخطي إلى نهاية هذه الصفحة.

برامج تسجيل الدخول

هذه المرة ، سوف نتحقق من العملية في جلسة تسجيل الدخول. يمكنك استخدام جلسات عمل أخرى، ولكن كن على دراية بالمهلة الافتراضية للجلسات.

بالنسبة لبرامج تسجيل الدخول ، يتم استخدام النصائح التالية دائما تقريبا ، لذا يرجى الرجوع إلى ما يلي للحصول على التفاصيل. لا يهم إذا كانت صفحات الحلاقة أو MVC.

هذه النصيحة تتعلق فقط بمهلات الجلسة ، لذلك لن أخوض في بقية التعليمات البرمجية. قم بتعديل مساحة الاسم لمطابقة مشروعك.

كود مشروع Razor Pages

Program.cs

using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authorization;

var builder = WebApplication.CreateBuilder(args);

// コンテナにサービスを追加します。
builder.Services.AddRazorPages();

// ※ここから追加

// Cookie による認証スキームを追加する
builder.Services
  .AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
  .AddCookie();

builder.Services.AddAuthorization(options =>
{
  // AllowAnonymous 属性が指定されていないすべての画面、アクションなどに対してユーザー認証が必要となる
  options.FallbackPolicy = new AuthorizationPolicyBuilder()
    .RequireAuthenticatedUser()
    .Build();
});

// ※ここまで追加

var app = builder.Build();

// HTTP リクエスト パイプラインを構成します。
if (!app.Environment.IsDevelopment())
{
  app.UseExceptionHandler("/Error");
  // デフォルトの HSTS 値は 30 日です。 運用シナリオではこれを変更することもできます。https://aka.ms/aspnetcore-hsts を参照してください。
  app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthentication(); // [追加] 認証
app.UseAuthorization(); // 認可

app.MapRazorPages();

app.Run();

الصفحات/الحساب/Login.cshtml.cs

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Security.Claims;

namespace SessionTimeoutExtensionIisRazorPages.Pages
{
  [AllowAnonymous]
  public class LoginModel : PageModel
  {
    /// <summary>ユーザー名。</summary>
    [BindProperty]
    [Required]
    [DisplayName("ユーザー名")]
    public string UserName { get; set; } = "";

    /// <summary>パスワード。</summary>
    [BindProperty]
    [Required]
    [DataType(DataType.Password)]
    [DisplayName("パスワード")]
    public string Password { get; set; } = "";

    /// <summary>仮のユーザーデータベースとする。</summary>
    private Dictionary<string, string> UserAccounts { get; set; } = new Dictionary<string, string>
    {
      { "user1", "password1" },
      { "user2", "password2" },
    };

    /// <summary>ログイン処理。</summary>
    public async Task<ActionResult> OnPost()
    {
      // 入力内容にエラーがある場合は処理を中断してエラー表示
      if (ModelState.IsValid == false) return Page();

      // ユーザーの存在チェックとパスワードチェック (仮実装)
      // 本 Tips は Cookie 認証ができるかどうかの確認であるため入力内容やパスワードの厳密なチェックは行っていません
      if (UserAccounts.TryGetValue(UserName, out string? getPass) == false || Password != getPass)
      {
        ModelState.AddModelError("", "ユーザー名またはパスワードが一致しません。");
        return Page();
      }

      // サインインに必要なプリンシパルを作る
      var claims = new[] { new Claim(ClaimTypes.Name, UserName) };
      var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
      var principal = new ClaimsPrincipal(identity);

      // 認証クッキーをレスポンスに追加
      await HttpContext.SignInAsync(principal);

      // ログインが必要な画面にリダイレクトします
      return RedirectToPage("/Index");
    }

    /// <summary>ログアウト処理。</summary>
    public async Task OnGetLogout()
    {
      // 認証クッキーをレスポンスから削除
      await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
    }
  }
}

الصفحات/الحساب/Login.cshtml

@page
@model LoginModel
@{}

<form asp-action="Login">
  <div class="row m-1 g-3">
    <div class="col-sm-6 offset-sm-3">
      <div asp-validation-summary="ModelOnly" class="text-danger"></div>
    </div>
  </div>

  <div class="row m-1 g-3">
    <div class="col-sm-6 offset-sm-3">
      <label asp-for="UserName" class="form-label"></label>
      <input asp-for="UserName" class="form-control" value="user1" />
      <span asp-validation-for="UserName" class="text-danger"></span>
    </div>
  </div>
  <div class="row m-1 g-3">
    <div class="col-sm-6 offset-sm-3">
      <label asp-for="Password" class="form-label"></label>
      <input asp-for="Password" class="form-control" value="password1" />
      <span asp-validation-for="Password" class="text-danger"></span>
    </div>
  </div>
  <div class="row m-1 g-3">
    <div class="col-sm-6 offset-sm-3">
      <button type="submit" class="btn btn-primary">ログイン</button>
    </div>
  </div>
  <div class="row m-1 g-3">
    <div class="col-sm-6 offset-sm-3">
      <a asp-page="/Index">認証が必要な画面へ直接リンク</a>
    </div>
  </div>
</form>

@section Scripts {
  @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
}

الصفحات/الفهرس.cshtml

@page
@model IndexModel
@{
  ViewData["Title"] = "Home page";
}

<div class="text-center">
  <h1 class="display-4">Welcome</h1>
  <p>Learn about <a href="https://learn.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>

<p>アクセス日時:@DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")</p>

الصفحات/المشتركة/_Layout.cshtml

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>@ViewData["Title"] - SessionTimeoutExtensionIisRazorPages</title>
  <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
  <link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
  <link rel="stylesheet" href="~/SessionTimeoutExtensionIisRazorPages.styles.css" asp-append-version="true" />
</head>
<body>
  <header>
    <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
      <div class="container">
        <a class="navbar-brand" asp-area="" asp-page="/Index">SessionTimeoutExtensionIisRazorPages</a>
        <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent"
                aria-expanded="false" aria-label="Toggle navigation">
          <span class="navbar-toggler-icon"></span>
        </button>
        <div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
          <ul class="navbar-nav flex-grow-1">
            <li class="nav-item">
              <a class="nav-link text-dark" asp-area="" asp-page="/Index">Home</a>
            </li>
            <li class="nav-item">
              <a class="nav-link text-dark" asp-area="" asp-page="/Privacy">Privacy</a>
            </li>
            @* ここから追加 *@
            <li class="nav-item">
              <a class="nav-link text-dark" asp-page="/Account/Login" asp-page-handler="Logout">ログアウト</a>
            </li>
            <li class="nav-item">
              <a class="nav-link text-dark" asp-page="/Account/Login">ログアウトせずログインへ</a>
            </li>
            @* ここまで追加 *@
          </ul>
        </div>
      </div>
    </nav>
  </header>
  <div class="container">
    <main role="main" class="pb-3">
      @RenderBody()
    </main>
  </div>

  <footer class="border-top footer text-muted">
    <div class="container">
      &copy; 2024 - SessionTimeoutExtensionIisRazorPages - <a asp-area="" asp-page="/Privacy">Privacy</a>
    </div>
  </footer>

  <script src="~/lib/jquery/dist/jquery.min.js"></script>
  <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
  <script src="~/js/site.js" asp-append-version="true"></script>

  @await RenderSectionAsync("Scripts", required: false)
</body>
</html>

رمز مشروع MVC

Program.cs

using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authorization;

var builder = WebApplication.CreateBuilder(args);

// コンテナにサービスを追加します。
builder.Services.AddControllersWithViews();

// ※ここから追加

// Cookie による認証スキームを追加する
builder.Services
  .AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
  .AddCookie();

builder.Services.AddAuthorization(options =>
{
  // AllowAnonymous 属性が指定されていないすべての画面、アクションなどに対してユーザー認証が必要となる
  options.FallbackPolicy = new AuthorizationPolicyBuilder()
    .RequireAuthenticatedUser()
    .Build();
});

// ※ここまで追加

var app = builder.Build();

// HTTP リクエスト パイプラインを構成します。
if (!app.Environment.IsDevelopment())
{
  app.UseExceptionHandler("/Home/Error");
  // デフォルトの HSTS 値は 30 日です。 運用シナリオではこれを変更することもできます。https://aka.ms/aspnetcore-hsts を参照してください。
  app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthentication(); // [追加] 認証
app.UseAuthorization(); // 認可

app.MapControllerRoute(name: "default", pattern: "{controller=Home}/{action=Index}/{id?}");

app.Run();

نماذج / LoginModel.cs

using System.ComponentModel;
using System.ComponentModel.DataAnnotations;

namespace SessionTimeoutExtensionIisMvc.Models
{
  public class LoginModel
  {
    /// <summary>ユーザー名。</summary>
    [Required]
    [DisplayName("ユーザー名")]
    public string UserName { get; set; } = "";

    /// <summary>パスワード。</summary>
    [Required]
    [DataType(DataType.Password)]
    [DisplayName("パスワード")]
    public string Password { get; set; } = "";
  }
}

وحدات التحكم / AccountController.cs

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using SessionTimeoutExtensionIisMvc.Models;
using System.Security.Claims;

namespace SessionTimeoutExtensionIisMvc.Controllers
{
  /// <remarks>
  /// <see cref="AllowAnonymous"/> 属性は Cookie 認証していなくてもアクセスできる Action (Controller) であることを示す。
  /// </remarks>
  [AllowAnonymous]
  public class AccountController : Controller
  {
    /// <summary>仮のユーザーデータベースとする。</summary>
    private Dictionary<string, string> UserAccounts { get; set; } = new Dictionary<string, string>
    {
      { "user1", "password1" },
      { "user2", "password2" },
    };

    /// <summary>ログイン画面を表示します。</summary>
    public IActionResult Login() => View();

    /// <summary>ログイン処理を実行します。</summary>
    [HttpPost]
    public async Task<IActionResult> Login(LoginModel model)
    {
      // 入力内容にエラーがある場合は処理を中断してエラー表示
      if (ModelState.IsValid == false) return View(model);

      // ユーザーの存在チェックとパスワードチェック (仮実装)
      // 本 Tips は Cookie 認証ができるかどうかの確認であるため入力内容やパスワードの厳密なチェックは行っていません
      if (UserAccounts.TryGetValue(model.UserName, out string? getPass) == false || model.Password != getPass)
      {
        ModelState.AddModelError("", "ユーザー名またはパスワードが一致しません。");
        return View(model);
      }

      // サインインに必要なプリンシパルを作る
      var claims = new[] { new Claim(ClaimTypes.Name, model.UserName) };
      var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
      var principal = new ClaimsPrincipal(identity);

      // 認証クッキーをレスポンスに追加
      await HttpContext.SignInAsync(principal);

      // ログインが必要な画面にリダイレクトします
      return RedirectToAction(nameof(HomeController.Index), "Home");
    }

    /// <summary>ログアウト処理を実行します。</summary>
    public async Task<IActionResult> Logout()
    {
      // 認証クッキーをレスポンスから削除
      await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);

      // ログイン画面にリダイレクト
      return RedirectToAction(nameof(Login));
    }
  }
}

المشاهدات / الحساب / Login.cshtml

@model LoginModel
@{}

<form asp-action="Login">
  <div class="row m-1 g-3">
    <div class="col-sm-6 offset-sm-3">
      <div asp-validation-summary="ModelOnly" class="text-danger"></div>
    </div>
  </div>

  <div class="row m-1 g-3">
    <div class="col-sm-6 offset-sm-3">
      <label asp-for="UserName" class="form-label"></label>
      <input asp-for="UserName" class="form-control" value="user1" />
      <span asp-validation-for="UserName" class="text-danger"></span>
    </div>
  </div>
  <div class="row m-1 g-3">
    <div class="col-sm-6 offset-sm-3">
      <label asp-for="Password" class="form-label"></label>
      <input asp-for="Password" class="form-control" value="password1" />
      <span asp-validation-for="Password" class="text-danger"></span>
    </div>
  </div>
  <div class="row m-1 g-3">
    <div class="col-sm-6 offset-sm-3">
      <button type="submit" class="btn btn-primary">ログイン</button>
    </div>
  </div>
  <div class="row m-1 g-3">
    <div class="col-sm-6 offset-sm-3">
      <a asp-controller="Home" asp-action="Index">認証が必要な画面へ直接リンク</a>
    </div>
  </div>
</form>

@section Scripts {
  @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
}

المشاهدات/الصفحة الرئيسية/Index.cshtml

@{
  ViewData["Title"] = "Home Page";
}

<div class="text-center">
  <h1 class="display-4">Welcome</h1>
  <p>Learn about <a href="https://learn.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>

<p>アクセス日時:@DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")</p>

المشاهدات / المشتركة / _Layout.cshtml

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>@ViewData["Title"] - SessionTimeoutExtensionIisMvc</title>
  <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
  <link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
  <link rel="stylesheet" href="~/SessionTimeoutExtensionIisMvc.styles.css" asp-append-version="true" />
</head>
<body>
  <header>
    <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
      <div class="container-fluid">
        <a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">SessionTimeoutExtensionIisMvc</a>
        <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent"
                aria-expanded="false" aria-label="Toggle navigation">
          <span class="navbar-toggler-icon"></span>
        </button>
        <div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
          <ul class="navbar-nav flex-grow-1">
            <li class="nav-item">
              <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
            </li>
            <li class="nav-item">
              <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
            </li>
            @* ここから追加 *@
            <li class="nav-item">
              <a class="nav-link text-dark" asp-controller="Account" asp-action="Logout">ログアウト</a>
            </li>
            <li class="nav-item">
              <a class="nav-link text-dark" asp-controller="Account" asp-action="Login">ログアウトせずログインへ</a>
            </li>
            @* ここまで追加 *@
          </ul>
        </div>
      </div>
    </nav>
  </header>
  <div class="container">
    <main role="main" class="pb-3">
      @RenderBody()
    </main>
  </div>

  <footer class="border-top footer text-muted">
    <div class="container">
      &copy; 2024 - SessionTimeoutExtensionIisMvc - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
    </div>
  </footer>
  <script src="~/lib/jquery/dist/jquery.min.js"></script>
  <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
  <script src="~/js/site.js" asp-append-version="true"></script>
  @await RenderSectionAsync("Scripts", required: false)
</body>
</html>

التحقق من العملية عن طريق تصحيح الأخطاء

تحقق من سلوك تسجيل الدخول وتأكد من أنه لا يمكنك الوصول إلى صفحات أخرى إذا لم تقم بتسجيل الدخول. يختلف وقت المهلة عند تصحيح الأخطاء محليا عن وقت التشغيل على IIS، لذلك لا تحتاج إلى التحقق من المهلة عند تصحيح الأخطاء.

نشر البرامج إلى IIS

قم بإعداد IIS ونشر البرنامج الذي قمت بإنشائه. لا يتم تغطية إعداد IIS هنا لأنه سيكون زائدا عن الحاجة. للحصول على تفسيرات مفصلة، راجع النصائح والمعلومات الأخرى أدناه.

التحقق من مهلات جلسة العمل للتطبيقات المنشورة على IIS

حتى الآن ، لم يقم البرنامج ولا IIS بتعيين مهلة الجلسة ، لذلك يجب أن يكون كل شيء افتراضيا. أولا ، قم بتسجيل الدخول واتركه لمدة 20 دقيقة على الأقل ، ثم Index حاول الوصول إلى الصفحة و Privacy . يمكنك الوصول إليه لمدة تصل إلى 20 دقيقة ، ولكن إذا انتهت المهلة ، فيجب نقلك إلى صفحة تسجيل الدخول.

تمديد فترة المهلة في "إدارة IIS"

إذا لم تقم بتعيين مهلة في البرنامج الخاص بك، يجب أن تكون قادرا على تمديد وقت المهلة في إعدادات تجمع التطبيقات الخاصة بك.

عند بدء تشغيل إدارة IIS، حدد تجمعات التطبيقات من القائمة الموجودة على اليمين. حدد تجمع التطبيقات الذي تستخدمه لتشغيل موقعك، ثم حدد إعدادات متقدمة من القائمة الموجودة على اليسار.

في مجموعة نموذج العملية ، يوجد عنصر يسمى مهلة الخمول (دقائق) ، لذا قم بتعيينه على أي مقدار من الوقت بالدقائق.

بعد الإعداد، قم بالتأكيد باستخدام الزر موافق ( OK) .

بعد ذلك ، يرجى التحقق من تشغيل مهلة الجلسة. إذا قمت بتعيينه على 60 دقيقة ، فسيكون ناجحا إذا لم تقم بتسجيل الخروج حتى إذا انتقلت الصفحة بعد 50 دقيقة من تسجيل الدخول.

بينما قد يرغب بعض الأشخاص في تمديد مقدار الوقت بين مهلات الجلسة قدر الإمكان ، فإن الحد الأقصى الذي يمكن تعيينه هو 29 ساعة. يتوافق هذا مع الوقت الذي يتم فيه إعادة تدوير تجمع التطبيقات. يمكنك أيضا تمديد وقت المهلة عن طريق تمديد وقت إعادة التدوير لتجمع التطبيقات. هناك أيضا قلق من أن الذاكرة المستخدمة ستستمر في البقاء ، لذلك إذا قمت بتغييرها ، فيرجى تعديلها وفقا للعملية.

أيضا ، حتى إذا قمت بتعيين قدر كبير من الوقت قبل انتهاء المهلة ، فغالبا ما تنتهي المهلة قبل ذلك. وذلك لأن تجمع التطبيقات يتم إعادة تدويره قبل انتهاء المهلة، أو ينتقل إلى حالة إيقاف مؤقت إذا لم يتم الوصول إليه لفترة من الوقت. إذا كنت تريد التأكد من الحفاظ على الجلسة لفترة زمنية محددة ، فأنت بحاجة إلى اتخاذ تدابير أخرى.