A munkamenet időtúllépésének növelése az IIS-en futó ASP.NET Core alkalmazások esetében
Művelet-ellenőrzési környezet
- Visual Studio
-
- Visual Studio 2022
- ASP.NET mag
-
- 8 (Borotvaoldalak, MVC)
- Windows Server
-
- 2022
- IIS
-
- 10.0
Működési környezet
Nem teszteltük minden esetben, de általában működnie kell a következő feltételek mellett:
- Visual Studio
-
- Bármi, ami fejleszthet egy ASP.NET Core projektet
- ASP.NET mag
-
- Bármely verzió (MVC, Razor Pages, API)
- Windows Server
-
- Windows Server 2008 vagy újabb
- IIS
-
- 7.0 vagy újabb
Először
A ASP.NET Core-ral írt alkalmazások egy "Kestrel" nevű egyszerű kiszolgálón futnak, és az időtartam, például a munkamenet időtúllépése főként programozott módon van beállítva.
Ha azonban IIS-t üzemeltet, és ASP.NET Core-alkalmazást futtat, előfordulhat, hogy felül szeretné bírálni az IIS-ben beállított értéket a programozott beállítással szemben.
Az ebben az időben leírt üresjárati idő miatti munkamenet-időtúllépést az IIS beállításai befolyásolják, ezért állítsuk be ezt. Ne feledje azonban, hogy a munkamenet idejét több beállítás is befolyásolja, ezért a beállítástól függően előfordulhat, hogy a munkamenet időkorlátja nem hosszabbítható meg ezzel a beállítással.
Ezt egy tesztprogrammal magyarázzuk, de ha gyors módszert szeretne beállítani, kérjük, ugorjon az oldal végére.
Bejelentkezési programok
Ezúttal ellenőrizzük a műveletet a bejelentkezési munkamenetben. Más munkameneteket is használhat, de vegye figyelembe a munkamenetek alapértelmezett időkorlátját.
A bejelentkezési programokhoz szinte mindig a következő tippeket használjuk, ezért kérjük, olvassa el a következőket a részletekért. Nem számít, hogy Razor Pages vagy MVC.
Ez a tipp csak a munkamenetek időtúllépéséről szól, ezért nem megyek bele a kód többi részébe. Módosítsa a névteret a projektnek megfelelően.
Razor Pages projekt kódja
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();
Oldalak/Fiók/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);
}
}
}
Oldalak/Fiók/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"); }
}
Oldalak/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>
Oldalak/Megosztott/_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 projekt kód
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();
Modellek/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; } = "";
}
}
Vezérlők/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));
}
}
}
Nézetek/Fiók/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"); }
}
Nézetek/Home/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>
Nézetek/Megosztott/_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>
A művelet ellenőrzése hibakereséssel
Ellenőrizze a bejelentkezési viselkedést, és győződjön meg arról, hogy nem tud hozzáférni más oldalakhoz, ha nincs bejelentkezve. A helyi hibakeresés időtúllépési ideje eltér az IIS-en való futtatástól, ezért hibakereséskor nem kell ellenőriznie az időtúllépést.
Programok központi telepítése az IIS szolgáltatásban
Állítsa be az IIS-t, és telepítse a létrehozott programot. Az IIS beállításával itt nem foglalkozunk, mert az redundáns lenne. Részletes magyarázatokért lásd alább a Tippek és egyéb információk részt.
- Az Internet Information Services (IIS) beállítása Windows Serveren
- ASP.NET Core programok távoli közzététele egy internetes IIS-webkiszolgálón
Munkamenet-időtúllépések ellenőrzése IIS-re telepített alkalmazások esetén
Eddig sem a program, sem az IIS nem állította be a munkamenet időtúllépését, így mindennek alapértelmezettnek kell lennie.
Először jelentkezzen be, és hagyja legalább 20 percig, majd Index
próbálja meg elérni az és Privacy
oldalt.
Legfeljebb 20 percig érheti el, de ha túllépi az időkorlátot, a bejelentkezési oldalra kell vinnie.
Az időtúllépési időszak meghosszabbítása az IIS-kezelőben
Ha nem állított be időtúllépést a programban, az alkalmazáskészlet beállításaiban meghosszabbíthatja azt.
Az IIS-kezelő indításakor válassza a bal oldali menü Alkalmazáskészletek elemét. Válassza ki a webhely működtetéséhez használt alkalmazáskészletet, majd válassza a jobb oldali menü Speciális beállítások elemét.
A Folyamatmodell csoportban található egy Üresjárati időkorlát (perc) nevű elem, ezért állítsa be tetszőleges időtartamra percben.
A beállítás után erősítse meg az OK gombbal.
Ezt követően ellenőrizze a munkamenet időtúllépésének működését. Ha 60 percre állítja, akkor sikeres lesz, ha nem jelentkezik ki, még akkor is, ha az oldal a bejelentkezés után 50 perccel átáll.
Bár egyesek a lehető legnagyobb mértékben szeretnék meghosszabbítani a munkamenetek időtúllépései közötti időt, a beállítható maximális érték 29 óra. Ez megfelel az alkalmazáskészlet újrahasznosítási idejének. Az időtúllépési időt az alkalmazáskészlet újrahasznosítási idejének meghosszabbításával is meghosszabbíthatja. Aggodalomra ad okot az is, hogy a használt memória továbbra is megmarad, ezért ha megváltoztatja, kérjük, állítsa be a műveletnek megfelelően.
Ezenkívül, még akkor is, ha nagy időt állít be az időtúllépés előtt, gyakran időtúllépés történik előtte. Ennek az az oka, hogy az alkalmazáskészletet a rendszer az időtúllépés lejárta előtt újrahasznosítja, vagy szüneteltetett állapotba kerül, ha egy ideig nem fértek hozzá. Ha biztosítani szeretné, hogy a munkamenet meghatározott ideig fennmaradjon, más intézkedéseket kell tennie.