De sessietime-out verhogen voor ASP.NET Core-toepassingen die op IIS worden uitgevoerd
Omgeving voor bedrijfsverificatie
- Visual Studio
-
- Visual Studio 2022
- ASP.NET kern
-
- 8 (Razor Pagina's, MVC)
- Windows Server
-
- 2022
- IIS (Engelstalig)
-
- 10.0
Werkomgeving
We hebben het niet in alle gevallen getest, maar het zou over het algemeen moeten werken onder de volgende omstandigheden:
- Visual Studio
-
- Alles wat een ASP.NET Core-project kan ontwikkelen
- ASP.NET kern
-
- Elke versie (MVC, Razor Pages, API)
- Windows Server
-
- Windows Server 2008 of hoger
- IIS (Engelstalig)
-
- 7.0 of hoger
Eerst
Applicaties die met ASP.NET Core zijn geschreven, draaien op een eenvoudige server genaamd "Kestrel", en de duur, zoals een time-out van de sessie, wordt voornamelijk programmatisch ingesteld.
Als u echter host in IIS en een ASP.NET Core-toepassing uitvoert, wilt u mogelijk de waarde overschrijven die is ingesteld in IIS via de programmatische instelling.
De sessietime-out als gevolg van inactieve tijd die deze tijd wordt beschreven, wordt beïnvloed door de IIS-instellingen, dus laten we deze instellen. Houd er echter rekening mee dat de sessietijd wordt beïnvloed door meerdere instellingen, dus afhankelijk van de instelling kan de sessietime-out mogelijk niet worden verlengd met deze instelling alleen.
Dit wordt uitgelegd met een testprogramma, maar als je een snelle manier wilt om het in te stellen, ga dan naar het einde van deze pagina.
Login Programma's
Deze keer controleren we de werking in de inlogsessie. U kunt andere sessies gebruiken, maar houd rekening met de standaardtime-out voor sessies.
Voor inlogprogramma's worden bijna altijd de volgende tips gebruikt, dus raadpleeg het volgende voor details. Het maakt niet uit of het Razor Pages of MVC is.
Deze tip gaat alleen over sessietime-outs, dus ik zal niet ingaan op de rest van de code. Wijzig de naamruimte zodat deze overeenkomt met uw project.
Razor Pages project code
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();
Pagina's/Account/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);
}
}
}
Pagina's/Account/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"); }
}
Pagina's/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>
Pagina's/Gedeeld/_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-projectcode
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();
Modellen/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; } = "";
}
}
Controllers/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));
}
}
}
Weergaven/Account/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"); }
}
Weergaven/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>
Weergaven/Gedeeld/_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>
De bewerking controleren door foutopsporing
Controleer het aanmeldingsgedrag en zorg ervoor dat u geen toegang hebt tot andere pagina's als u niet bent ingelogd. De time-outtijd bij het lokaal opsporen van foutopsporing verschilt van bij het uitvoeren van IIS, dus u hoeft de time-out niet te controleren bij het opsporen van fouten.
Programma's implementeren in IIS
Stel IIS in en implementeer het programma dat u hebt gemaakt. Het opzetten van IIS valt hier niet onder omdat het overbodig zou zijn. Zie Tips en andere informatie hieronder voor gedetailleerde uitleg.
- Internet Information Services (IIS) instellen op Windows Server
- Publiceer ASP.NET Core-programma's op afstand naar een IIS-webserver op internet
Time-outs voor sessies controleren voor toepassingen die zijn geïmplementeerd in IIS
Tot nu toe heeft noch het programma, noch IIS de sessietime-out ingesteld, dus alles zou standaard moeten zijn.
Log eerst in en laat het minstens 20 minuten staan, en probeer vervolgens Index
toegang te krijgen tot de pagina en Privacy
.
U hebt er maximaal 20 minuten toegang toe, maar als er een time-out optreedt, moet u naar de inlogpagina worden geleid.
De time-outperiode verlengen in IIS-beheer
Als u geen time-out hebt ingesteld in uw programma, moet u de time-outtijd kunnen verlengen in de instellingen van uw toepassingsgroep.
Wanneer u IIS-beheer start, selecteert u Groepen van toepassingen in het menu aan de linkerkant. Selecteer de groep van toepassingen die u gebruikt om uw site te beheren en selecteer vervolgens Geavanceerde instellingen in het menu aan de rechterkant.
In de groep Procesmodel is er een item met de naam Time-out bij inactiviteit (minuten), dus stel dit in op een willekeurige hoeveelheid tijd in minuten.
Bevestig na het instellen met de OK-knop.
Controleer daarna de werking van de sessietime-out. Als u deze instelt op 60 minuten, is het succesvol als u niet bent uitgelogd, zelfs als de pagina-overgangen 50 minuten na het inloggen worden uitgevoerd.
Hoewel sommige mensen de tijd tussen de time-outs van sessies zo veel mogelijk willen verlengen, is het maximum dat kan worden ingesteld 29 uur. Dit komt overeen met het tijdstip waarop de toepassingspool wordt gerecycled. U kunt de time-outtijd ook verlengen door de recycletijd van de toepassingsgroep te verlengen. Er is ook bezorgdheid dat het gebruikte geheugen zal blijven bestaan, dus als u het wijzigt, pas het dan aan volgens de bewerking.
En zelfs als u een grote hoeveelheid tijd voor de time-out instelt, treedt er vaak een time-out op. Dit komt omdat de toepassingsgroep wordt gerecycled voordat de time-out verloopt, of omdat deze de status Onderbroken krijgt als deze een tijdje niet is geopend. Als u er zeker van wilt zijn dat de sessie gedurende een bepaalde tijd wordt volgehouden, moet u andere maatregelen nemen.