Google Code Prettify

在 ASP.NET Core MVC 應用中實現使用 JWT 的登入功能並將 JWT token 保存到 Session 中

在 ASP.NET Core MVC 應用中實現使用 JWT 的登入功能並將 JWT token 保存到 Session 中,涉及以下步驟:

創建登入頁面:用戶輸入他們的憑證(如用戶名和密碼)。
發送登入請求:從 MVC 應用發送一個請求到 API 來獲取 JWT。
存儲 JWT:將 JWT 存儲在 Session 中。
設置授權標頭:在後續請求中使用 JWT 進行身份驗證。



步驟 1:創建登入頁面
首先,在你的 MVC 應用中創建一個簡單的登入頁面,讓用戶輸入用戶名和密碼。

html

<!-- Views/Account/Login.cshtml -->
@{
    ViewData["Title"] = "Login";
}

<h2>@ViewData["Title"]</h2>

<form asp-action="Login" method="post">
    <div>
        <label asp-for="Username"></label>
        <input asp-for="Username" />
    </div>
    <div>
        <label asp-for="Password"></label>
        <input asp-for="Password" type="password" />
    </div>
    <button type="submit">Login</button>
</form>



步驟 2:創建登入模型
在 MVC 應用中創建一個模型來綁定登入頁面的輸入。

csharp

// Models/LoginViewModel.cs
using System.ComponentModel.DataAnnotations;

public class LoginViewModel
{
    [Required]
    public string Username { get; set; }

    [Required]
    public string Password { get; set; }
}



步驟 3:創建控制器來處理登入請求
創建一個控制器來處理登入邏輯,包括發送請求到 API 並獲取 JWT,然後將 JWT 存儲在 Session 中。

csharp

// Controllers/AccountController.cs
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using YourNamespace.Models;

public class AccountController : Controller
{
    private readonly IHttpClientFactory _httpClientFactory;

    public AccountController(IHttpClientFactory httpClientFactory)
    {
        _httpClientFactory = httpClientFactory;
    }

    [HttpGet]
    public IActionResult Login()
    {
        return View();
    }

    [HttpPost]
    public async Task<IActionResult> Login(LoginViewModel model)
    {
        if (!ModelState.IsValid)
        {
            return View(model);
        }

        var client = _httpClientFactory.CreateClient();
        var loginUrl = "https://yourapi.com/api/auth/login";
        var loginData = new
        {
            Username = model.Username,
            Password = model.Password
        };

        var content = new StringContent(JsonSerializer.Serialize(loginData), Encoding.UTF8, "application/json");
        var response = await client.PostAsync(loginUrl, content);

        if (response.IsSuccessStatusCode)
        {
            var responseString = await response.Content.ReadAsStringAsync();
            var jwt = JsonSerializer.Deserialize<JwtResponse>(responseString);

            // 存儲 JWT 到 Session
            HttpContext.Session.SetString("JWT", jwt.Token);

            return RedirectToAction("Index", "Home");
        }

        ModelState.AddModelError(string.Empty, "Invalid login attempt.");
        return View(model);
    }
}

public class JwtResponse
{
    public string Token { get; set; }
}



步驟 4:配置 Session
在 Startup.cs 中配置 Session。

csharp

public void ConfigureServices(IServiceCollection services)
{
    services.AddHttpClient();
    services.AddControllersWithViews();
    services.AddSession(options =>
    {
        options.IdleTimeout = TimeSpan.FromMinutes(30); // 可以根據需求調整
        options.Cookie.HttpOnly = true;
        options.Cookie.IsEssential = true;
    });
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

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

    app.UseSession(); // 必須在 UseRouting 和 UseAuthentication 之間
    app.UseAuthentication();
    app.UseAuthorization();

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



步驟 5:設置授權標頭
在每次發送 HTTP 請求時,從 Session 中獲取 JWT 並設置授權標頭。

csharp

public class AuthorizedHttpClientHandler : DelegatingHandler
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public AuthorizedHttpClientHandler(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var token = _httpContextAccessor.HttpContext.Session.GetString("JWT");
        if (!string.IsNullOrEmpty(token))
        {
            request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
        }

        return await base.SendAsync(request, cancellationToken);
    }
}

public void ConfigureServices(IServiceCollection services)
{
    services.AddHttpClient("AuthorizedClient")
        .AddHttpMessageHandler<AuthorizedHttpClientHandler>();

    services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
    services.AddTransient<AuthorizedHttpClientHandler>();

    services.AddControllersWithViews();
    services.AddSession(options =>
    {
        options.IdleTimeout = TimeSpan.FromMinutes(30);
        options.Cookie.HttpOnly = true;
        options.Cookie.IsEssential = true;
    });
}

使用 AuthorizedHttpClient 發送請求
在需要授權的請求中使用 AuthorizedHttpClient。

csharp

public class SomeController : Controller
{
    private readonly IHttpClientFactory _httpClientFactory;

    public SomeController(IHttpClientFactory httpClientFactory)
    {
        _httpClientFactory = httpClientFactory;
    }

    public async Task<IActionResult> SomeAction()
    {
        var client = _httpClientFactory.CreateClient("AuthorizedClient");
        var response = await client.GetAsync("https://yourapi.com/api/protectedresource");

        if (response.IsSuccessStatusCode)
        {
            var data = await response.Content.ReadAsStringAsync();
            // 處理數據
        }
        else
        {
            // 處理錯誤
        }

        return View();
    }
}



將這些部分組合起來,你將擁有一個完整的 MVC 應用,允許用戶登入並將 JWT 存儲在 Session 中,從而在後續的請求中使用這個 JWT 進行身份驗證。

這種方式不僅實現了基於 JWT 的身份驗證,還充分利用了 ASP.NET Core 的 Session 管理功能來安全地存儲和使用 JWT。