การเพิ่มการหมดเวลาเซสชันสําหรับโปรแกรมประยุกต์หลัก ASP.NET ที่ทํางานบน IIS
สภาพแวดล้อมการตรวจสอบการทํางาน
- วิชวลสตูดิโอ
-
- วิชวลสตูดิโอ 2022
- แกน ASP.NET
-
- 8 (หน้ามีดโกน, MVC)
- เซิร์ฟเวอร์ Windows
-
- 2022
- ไอเอส
-
- 10.0
สภาพแวดล้อมในการทํางาน
เราไม่ได้ทดสอบในทุกกรณี แต่ควรทํางานโดยทั่วไปภายใต้เงื่อนไขต่อไปนี้:
- วิชวลสตูดิโอ
-
- อะไรก็ได้ที่สามารถพัฒนาโครงการ ASP.NET Core ได้
- แกน ASP.NET
-
- เวอร์ชันใดก็ได้ (MVC, Razor Pages, API)
- เซิร์ฟเวอร์ Windows
-
- Windows Server 2008 หรือใหม่กว่า
- ไอเอส
-
- 7.0 หรือใหม่กว่า
ทีแรก
แอปพลิเคชันที่เขียนด้วย ASP.NET Core ทํางานบนเซิร์ฟเวอร์อย่างง่ายที่เรียกว่า "Kestrel" และระยะเวลาเช่นการหมดเวลาของเซสชันจะถูกตั้งค่าโดยทางโปรแกรมเป็นหลัก
อย่างไรก็ตาม ถ้าคุณกําลังโฮสต์บน IIS และเรียกใช้โปรแกรมประยุกต์ ASP.NET Core คุณอาจต้องการแทนที่ค่าที่ตั้งไว้ใน IIS ผ่านการตั้งค่าแบบเป็นโปรแกรม
การหมดเวลาของเซสชันเนื่องจากเวลาว่างที่อธิบายไว้ในครั้งนี้ได้รับผลกระทบจากการตั้งค่า IIS ดังนั้นเรามาตั้งค่านี้ อย่างไรก็ตาม โปรดทราบว่าเวลาเซสชันได้รับผลกระทบจากการตั้งค่าหลายอย่าง ดังนั้น ขึ้นอยู่กับการตั้งค่า ระยะหมดเวลาของเซสชันอาจไม่ขยายออกไปด้วยการตั้งค่านี้เพียงอย่างเดียว
สิ่งนี้อธิบายด้วยโปรแกรมทดสอบ แต่ถ้าคุณต้องการวิธีที่รวดเร็วในการตั้งค่าโปรดข้ามไปที่ส่วนท้ายของหน้านี้
โปรแกรมเข้าสู่ระบบ
คราวนี้เราจะตรวจสอบการดําเนินการในเซสชันการเข้าสู่ระบบ คุณสามารถใช้เซสชันอื่นได้ แต่ระวังการหมดเวลาเริ่มต้นสําหรับเซสชัน
สําหรับโปรแกรมเข้าสู่ระบบเคล็ดลับต่อไปนี้มักใช้เกือบทุกครั้งดังนั้นโปรดดูรายละเอียดต่อไปนี้ ไม่สําคัญว่าจะเป็น Razor Pages หรือ 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"); }
}
หน้า/Index.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">
© 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">
© 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 ไม่ครอบคลุมที่นี่เนื่องจากจะซ้ําซ้อน สําหรับคําอธิบายโดยละเอียด โปรดดูเคล็ดลับและข้อมูลอื่นๆ ด้านล่าง
- การตั้งค่า Internet Information Services (IIS) บน Windows Server
- เผยแพร่โปรแกรม ASP.NET Core จากระยะไกลไปยังเว็บเซิร์ฟเวอร์ IIS บนอินเทอร์เน็ต
การตรวจสอบการหมดเวลาของเซสชันสําหรับโปรแกรมประยุกต์ที่ปรับใช้บน IIS
จนถึงตอนนี้ ทั้งโปรแกรมและ IIS ยังไม่ได้ตั้งค่าการหมดเวลาของเซสชัน ดังนั้นทุกอย่างควรเป็นค่าเริ่มต้น
ขั้นแรก ให้เข้าสู่ระบบและปล่อยทิ้งไว้อย่างน้อย 20 นาที จากนั้น Index
ลองเข้าถึงหน้า และ Privacy
.
คุณสามารถเข้าถึงได้นานถึง 20 นาที แต่ถ้าหมดเวลา คุณควรเข้าสู่หน้าเข้าสู่ระบบ
ขยายระยะเวลาการหมดเวลาในตัวจัดการ IIS
หากคุณไม่ได้ตั้งค่าการหมดเวลาในโปรแกรมของคุณ คุณควรจะสามารถขยายเวลาหมดเวลาในการตั้งค่าพูลแอปพลิเคชันของคุณได้
เมื่อคุณเริ่มตัวจัดการ IIS เลือกพูลโปรแกรมประยุกต์จากเมนูทางด้านซ้าย เลือกพูลแอปพลิเคชันที่คุณใช้เพื่อใช้งานไซต์ของคุณ จากนั้นเลือก การตั้งค่าขั้นสูง จากเมนูทางด้านขวา
ในกลุ่ม ตัวแบบกระบวนการ มีรายการที่เรียกว่า Idle Timeout (นาที) ดังนั้นให้ตั้งค่าเป็นจํานวนครั้งใดก็ได้ในหน่วยนาที
หลังจากตั้งค่าแล้ว ให้ยืนยันด้วยปุ่ม OK
หลังจากนั้น โปรดตรวจสอบการทํางานของการหมดเวลาเซสชัน หากคุณตั้งค่าเป็น 60 นาที จะสําเร็จหากคุณไม่ได้ออกจากระบบแม้ว่าหน้าจะเปลี่ยน 50 นาทีหลังจากเข้าสู่ระบบ
แม้ว่าบางคนอาจต้องการขยายระยะเวลาระหว่างการหมดเวลาของเซสชันให้มากที่สุด แต่ค่าสูงสุดที่สามารถตั้งค่าได้คือ 29 ชั่วโมง ซึ่งสอดคล้องกับเวลาที่พูลแอปพลิเคชันถูกรีไซเคิล คุณยังสามารถขยายเวลาหมดเวลาได้โดยขยายเวลารีไซเคิลของพูลแอปพลิเคชัน นอกจากนี้ยังมีข้อกังวลว่าหน่วยความจําที่ใช้แล้วจะยังคงหลงเหลืออยู่ดังนั้นหากคุณเปลี่ยนโปรดปรับเปลี่ยนตามการทํางาน
นอกจากนี้ แม้ว่าคุณจะตั้งเวลาจํานวนมากก่อนหมดเวลา แต่ก็มักจะหมดเวลาก่อนหน้านั้น นี่เป็นเพราะพูลแอปพลิเคชันถูกรีไซเคิลก่อนที่การหมดเวลาจะหมดอายุ หรือเข้าสู่สถานะหยุดชั่วคราวหากไม่มีการเข้าถึงชั่วขณะหนึ่ง หากคุณต้องการให้แน่ใจว่าเซสชันได้รับการดูแลตามระยะเวลาที่กําหนดคุณต้องใช้มาตรการอื่น ๆ