ASP.NET Core Identity에서 JWT Refresh Token 적용 및 테스트하기
추천 자료: ASP.NET Core 인증 및 권한 부여
이 문서에서는 ASP.NET Core Identity와 JWT Refresh Token을 활용하여 인증 시스템을 구축하는 방법을 단계별로 설명합니다.
완성된 API를 .http
파일을 이용해 테스트하는 방법까지 포함하므로, 직접 따라하며 실습할 수 있습니다.
1. 프로젝트 환경 설정
1.1. 필요한 패키지 설치
ASP.NET Core에서 JWT 인증과 Identity를 사용하기 위해 NuGet 패키지를 설치해야 합니다.
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer
dotnet add package Microsoft.AspNetCore.Identity.EntityFrameworkCore
dotnet add package Microsoft.AspNetCore.Identity
이 패키지들은 다음과 같은 역할을 합니다.
Microsoft.AspNetCore.Authentication.JwtBearer
: JWT 기반 인증을 수행할 수 있도록 설정하는 패키지Microsoft.AspNetCore.Identity.EntityFrameworkCore
: Identity를 사용하여 사용자 계정 관리를 쉽게 구현하는 패키지Microsoft.AspNetCore.Identity
: ASP.NET Core Identity의 핵심 기능을 제공하는 패키지
2. Identity 및 JWT 설정
2.1. 사용자 엔터티(User Entity) 수정
IdentityUser
를 확장하여 Refresh Token 관련 필드를 추가합니다.
using Microsoft.AspNetCore.Identity;
using System;
public class ApplicationUser : IdentityUser
{
public string? RefreshToken { get; set; }
public DateTime? RefreshTokenExpiryTime { get; set; }
}
위 코드에서 RefreshToken
과 RefreshTokenExpiryTime
을 추가하여 사용자가 새로운 액세스 토큰을 받을 수 있도록 저장할 공간을 마련합니다.
2.2. JWT 설정 추가 (appsettings.json
)
JWT 관련 설정을 appsettings.json
에 추가합니다.
"JwtSettings": {
"Secret": "{JwtSecret}",
"Issuer": "https://your-api.com",
"Audience": "https://your-client.com",
"AccessTokenExpiration": 30,
"RefreshTokenExpiration": 7
}
각 항목의 의미는 다음과 같습니다.
Secret
: JWT 서명을 위한 보안 키. 반드시 강력한 값을 사용해야 하며, 환경 변수에서 관리하는 것이 좋습니다.Issuer
: JWT를 발급하는 서버의 도메인 또는 서비스 이름.Audience
: 이 토큰을 사용할 클라이언트(웹 애플리케이션, 모바일 앱 등).AccessTokenExpiration
: 액세스 토큰 만료 시간(분 단위).RefreshTokenExpiration
: 리프레시 토큰 만료 시간(일 단위).
환경 변수에서 Secret
값 가져오기 (Program.cs
)
운영 환경에서는 .env
파일 또는 환경 변수에서 JwtSecret
값을 관리하는 것이 보안에 더 좋습니다.
var secretKey = Environment.GetEnvironmentVariable("JwtSecret") ?? configuration["JwtSettings:Secret"];
3. JWT 및 Identity 설정 (Program.cs
)
JWT 및 ASP.NET Core Identity를 설정하여 사용자 인증과 토큰 발급을 수행할 준비를 합니다.
using System.Text;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
var builder = WebApplication.CreateBuilder(args);
var configuration = builder.Configuration;
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(configuration.GetConnectionString("DefaultConnection")));
builder.Services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
var jwtSettings = configuration.GetSection("JwtSettings");
var key = Encoding.UTF8.GetBytes(jwtSettings["Secret"]);
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.RequireHttpsMetadata = false;
options.SaveToken = true;
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = jwtSettings["Issuer"],
ValidAudience = jwtSettings["Audience"],
IssuerSigningKey = new SymmetricSecurityKey(key)
};
});
var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
4. JWT 및 Refresh Token 생성
4.1. JWT 및 Refresh Token 생성 서비스
JWT 및 Refresh Token을 생성하는 서비스를 추가합니다.
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
public class JwtService
{
private readonly IConfiguration _configuration;
public JwtService(IConfiguration configuration)
{
_configuration = configuration;
}
public string GenerateAccessToken(IEnumerable<Claim> claims)
{
var jwtSettings = _configuration.GetSection("JwtSettings");
var key = Encoding.UTF8.GetBytes(jwtSettings["Secret"]);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(claims),
Expires = DateTime.UtcNow.AddMinutes(Convert.ToDouble(jwtSettings["AccessTokenExpiration"])),
Issuer = jwtSettings["Issuer"],
Audience = jwtSettings["Audience"],
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
};
var tokenHandler = new JwtSecurityTokenHandler();
var token = tokenHandler.CreateToken(tokenDescriptor);
return tokenHandler.WriteToken(token);
}
public string GenerateRefreshToken()
{
return Convert.ToBase64String(RandomNumberGenerator.GetBytes(64));
}
}
5. 인증 관련 API 구현 (AuthController.cs
)
사용자 인증 및 토큰 관리를 위한 컨트롤러를 구현합니다.
[Route("api/auth")]
[ApiController]
public class AuthController : ControllerBase
{
private readonly UserManager<ApplicationUser> _userManager;
private readonly JwtService _jwtService;
public AuthController(UserManager<ApplicationUser> userManager, JwtService jwtService)
{
_userManager = userManager;
_jwtService = jwtService;
}
[HttpPost("register")]
public async Task<IActionResult> Register([FromBody] RegisterModel model)
{
var user = new ApplicationUser { UserName = model.Username, Email = model.Email };
var result = await _userManager.CreateAsync(user, model.Password);
if (!result.Succeeded)
return BadRequest(result.Errors);
return Ok(new { message = "User registered successfully" });
}
[HttpPost("login")]
public async Task<IActionResult> Login([FromBody] LoginModel model)
{
var user = await _userManager.FindByNameAsync(model.Username);
if (user == null || !await _userManager.CheckPasswordAsync(user, model.Password))
return Unauthorized();
var accessToken = _jwtService.GenerateAccessToken(new[] { new Claim(ClaimTypes.Name, user.UserName) });
var refreshToken = _jwtService.GenerateRefreshToken();
user.RefreshToken = refreshToken;
user.RefreshTokenExpiryTime = DateTime.UtcNow.AddDays(7);
await _userManager.UpdateAsync(user);
return Ok(new { accessToken, refreshToken });
}
}
6. .http
파일을 사용한 테스트
API가 정상적으로 동작하는지 확인하기 위해 .http
파일을 작성하여 요청을 테스트할 수 있습니다.
POST http://localhost:5000/api/auth/register
Content-Type: application/json
{
"username": "testuser",
"email": "test@example.com",
"password": "Test@1234"
}
POST http://localhost:5000/api/auth/login
Content-Type: application/json
{
"username": "testuser",
"password": "Test@1234"
}
이제 JWT 및 Refresh Token을 이용한 인증 시스템이 완성되었습니다.
추천 자료: .NET Blazor에 대해 알아보시겠어요? .NET Blazor 알아보기를 확인해보세요!