- IJwtService/JwtService에 GetTokenInfo(JTI, 만료시간 추출) 추가
- LogoutAsync에 Redis 블랙리스트 로직 추가 (key: blacklist:{jti}, TTL: 남은 만료시간)
- AuthenticationExtensions OnTokenValidated에서 블랙리스트 체크
- 로그아웃 후 동일 Access Token 재사용 시 401 반환
Closes #169
73 lines
2.5 KiB
C#
73 lines
2.5 KiB
C#
using System.Text;
|
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
|
using Microsoft.IdentityModel.Tokens;
|
|
using SPMS.Application.Interfaces;
|
|
using SPMS.Application.Settings;
|
|
|
|
namespace SPMS.API.Extensions;
|
|
|
|
public static class AuthenticationExtensions
|
|
{
|
|
public static IServiceCollection AddJwtAuthentication(
|
|
this IServiceCollection services,
|
|
IConfiguration configuration)
|
|
{
|
|
var jwtSettings = configuration.GetSection(JwtSettings.SectionName).Get<JwtSettings>()!;
|
|
|
|
services.Configure<JwtSettings>(configuration.GetSection(JwtSettings.SectionName));
|
|
|
|
services.AddAuthentication(options =>
|
|
{
|
|
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
|
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
|
|
})
|
|
.AddJwtBearer(options =>
|
|
{
|
|
options.TokenValidationParameters = new TokenValidationParameters
|
|
{
|
|
ValidateIssuer = true,
|
|
ValidateAudience = true,
|
|
ValidateLifetime = true,
|
|
ValidateIssuerSigningKey = true,
|
|
ValidIssuer = jwtSettings.Issuer,
|
|
ValidAudience = jwtSettings.Audience,
|
|
IssuerSigningKey = new SymmetricSecurityKey(
|
|
Encoding.UTF8.GetBytes(jwtSettings.SecretKey)),
|
|
ClockSkew = TimeSpan.Zero
|
|
};
|
|
|
|
options.Events = new JwtBearerEvents
|
|
{
|
|
OnTokenValidated = async context =>
|
|
{
|
|
var tokenStore = context.HttpContext.RequestServices
|
|
.GetRequiredService<ITokenStore>();
|
|
var jti = context.Principal?.FindFirst("jti")?.Value;
|
|
if (!string.IsNullOrEmpty(jti))
|
|
{
|
|
var blacklisted = await tokenStore.GetAsync($"blacklist:{jti}");
|
|
if (blacklisted != null)
|
|
context.Fail("토큰이 무효화되었습니다.");
|
|
}
|
|
}
|
|
};
|
|
});
|
|
|
|
return services;
|
|
}
|
|
|
|
public static IServiceCollection AddAuthorizationPolicies(this IServiceCollection services)
|
|
{
|
|
services.AddAuthorization(options =>
|
|
{
|
|
options.AddPolicy("SuperOnly", policy =>
|
|
policy.RequireRole("Super"));
|
|
|
|
options.AddPolicy("ManagerOrAbove", policy =>
|
|
policy.RequireRole("Super", "Manager"));
|
|
});
|
|
|
|
return services;
|
|
}
|
|
}
|