Blazor에서 토큰 기반 인증 구현(Identity를 이용한 로그인)
작성날짜 2025/03/31
인증서비스 사용 설정
Program.cs
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options =>
{
options.Cookie.Name = "auth_token"; //쿠키 이름
options.LoginPath = "/login"; // 로그인 페이지
options.Cookie.MaxAge = TimeSpan.FromMinutes(30); // 쿠키 유효시간, 30분으로 설정
options.AccessDeniedPath = "/access-denied"; // 거부 페이지
}); // 인증 서비스 추가
builder.Services.AddCascadingAuthenticationState();
app.UseAuthentication(); // 인증 서비스 사용
위와 같이 서비스를 등록해준다.
여기서 어떤 방식으로 인증을 할지, 인증의 유효 기간 등을 설정할 수 있다.
우리는 쿠키 방식으로 인증을 하고 쿠키의 이름은 'auth_token', 유효 기간은 30분이다.
로그인 페이지
아래와 같이 로그인 페이지를 만들어주자.
/login
@page "/login"
@using System.Security.Claims
@using Microsoft.AspNetCore.Authentication
@using Microsoft.AspNetCore.Authentication.Cookies
@inject NavigationManager navigationManager
@inject IJSRuntime jsRuntime
<h3>Login</h3>
<EditForm Model="@Model" OnSubmit="SignIn" FormName="SignInForm">
<InputText type="text" @bind-Value="Model.UserID" placeholder="ID" />
<InputText type="password" @bind-Value="Model.Password" placeholder="Password" />
<button type="submit">Login</button>
</EditForm>
@code {
[CascadingParameter]
public HttpContext HttpContext { get; set; } = default!;
[SupplyParameterFromForm]
public LoginModel Model { get; set; } = new LoginModel();
private async Task SignIn()
{
if (Model.UserID == "pinya" && Model.Password == "1234")
{
var claims = new List<Claim> // 인증된 사용자의 정보들
{
new Claim(ClaimTypes.Name, Model.UserID), // 사용자의 이름
new Claim(ClaimTypes.Role, "admin") // 사용자의 역할
};
var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme); // 인증 정보
var principal = new ClaimsPrincipal(identity); // 유저 정보
await HttpContext.SignInAsync(principal); // 유저 정보로 로그인
navigationManager.NavigateTo("/"); // 로그인 후 이동할 페이지
}
else
{
await jsRuntime.InvokeVoidAsync("alert", "Wrong user infomation");
}
}
public class LoginModel
{
public string UserID { get; set; } = string.Empty;
public string Password { get; set; } = string.Empty;
}
}
로그인 페이지가 생각보다 복잡하다. 그냥 input 태그에 button만 두고 로그인 함수를 실행하면 될 것 같은데 EditForm에 Model도 지정하고 ID와 Password도 변수를 만들어서 바인딩하지 않고 굳이 LoginModel을 만들어서 접근한다.
이러는 이유는 Blazor의 특성 때문인데, MSDN의 Blazor에서 HttpContext 사용하기 글을 보면 대화형 페이지에서는 HttpContext가 존재하지 않기 때문에 사용자체가 불가능 하다. 그래서 나도 굳이 InteractionServer모드로 실행해 봤는데 HttpContext가 존재하지 않아서 SignIn이 불가능 했다.
그래서 위와 같이 작성하고 로그인을 하면...
로그인 전엔 auth_token이 없지만
로그인 후에 auth_token이 생성된다.
이 auth_token은 정보가 암호화되어 쉽게 정보를 알아낼 수 없다. 하지만 이 토큰 자체가 인증 정보이기도 하므로 이 토큰을 가지고 있는 누군가가 토큰의 원래 주인인 것처럼 권한을 얻을 수도 있으니 브라우저 보안에도 신경을 써야한다.
정보가 제대로 저장되었는지 확인을 위해 아래와 같이 새로운 페이지를 만들자.
/check-user
@page "/check-user"
@using System.Security.Claims
<h3>CheckUser</h3>
@code {
[CascadingParameter]
public HttpContext HttpContext { get; set; } = default!;
protected override void OnInitialized()
{
base.OnInitialized();
var user = HttpContext.User;
if (user.Identity.IsAuthenticated)
{
// 인증된 사용자
var name = user.Identity.Name;
var role = user.FindFirst(ClaimTypes.Role)?.Value;
Console.WriteLine($"User: {name}, Role: {role}");
}
else
{
// 인증되지 않은 사용자
Console.WriteLine("User is not authenticated.");
}
}
}
로그인 후 이 페이지에 접속하면
암호화 됐던 사용자 정보를 확인할 수 있다.
기타
로그인 부분에서 Claim, ClaimsIdentity, ClaimsPrincipal이라는 처음 보는 클래스가 등장해서 이 글이 이해하는데 도움이 됐다. 쉽게 말해 Claim은 개별 정보(이름, 역할 등), ClaimsIdentity는 인증 정보(일반 사용자 계정, 관리자 계정), ClaimsPrincipal은 사용자가 된다.