Skip to content

Commit 9ad211b

Browse files
committed
로그인 로직 수정
1 parent e6ea4a2 commit 9ad211b

File tree

7 files changed

+163
-191
lines changed

7 files changed

+163
-191
lines changed

ProjectVG.Api/Controllers/AuthController.cs

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,26 @@
44
namespace ProjectVG.Api.Controllers
55
{
66
[ApiController]
7-
[Route("api/v1/[controller]")]
7+
[Route("api/v1/auth")]
88
public class AuthController : ControllerBase
99
{
10-
private readonly IAuthService _authService;
10+
private readonly IUserAuthService _authService;
1111

12-
public AuthController(IAuthService authService)
12+
public AuthController(IUserAuthService authService)
1313
{
1414
_authService = authService;
1515
}
1616

17+
/// <summary>
18+
/// Access Token 갱신
19+
/// </summary>
1720
[HttpPost("refresh")]
1821
public async Task<IActionResult> RefreshToken()
1922
{
2023
var refreshToken = GetRefreshTokenFromHeader();
21-
var result = await _authService.RefreshTokenAsync(refreshToken);
22-
23-
return Ok(new
24-
{
24+
var result = await _authService.RefreshAccessTokenAsync(refreshToken);
25+
26+
return Ok(new {
2527
success = true,
2628
tokens = result.Tokens,
2729
user = result.User
@@ -33,9 +35,8 @@ public async Task<IActionResult> Logout()
3335
{
3436
var refreshToken = GetRefreshTokenFromHeader();
3537
var success = await _authService.LogoutAsync(refreshToken);
36-
37-
return Ok(new
38-
{
38+
39+
return Ok(new {
3940
success = success,
4041
message = success ? "Logout successful" : "Logout failed"
4142
});
@@ -44,15 +45,13 @@ public async Task<IActionResult> Logout()
4445
[HttpPost("guest-login")]
4546
public async Task<IActionResult> GuestLogin([FromBody] string guestId)
4647
{
47-
if (string.IsNullOrEmpty(guestId))
48-
{
48+
if (string.IsNullOrEmpty(guestId)) {
4949
throw new ValidationException(ErrorCode.GUEST_ID_INVALID);
5050
}
5151

52-
var result = await _authService.LoginWithOAuthAsync("guest", guestId);
53-
54-
return Ok(new
55-
{
52+
var result = await _authService.SignInWithOAuthAsync("guest", guestId);
53+
54+
return Ok(new {
5655
success = true,
5756
tokens = result.Tokens,
5857
user = result.User
@@ -64,4 +63,4 @@ private string GetRefreshTokenFromHeader()
6463
return Request.Headers["X-Refresh-Credit"].FirstOrDefault() ?? string.Empty;
6564
}
6665
}
67-
}
66+
}

ProjectVG.Api/Controllers/OAuthController.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ public async Task<IActionResult> OAuth2Callback(
8585
return Redirect(result.RedirectUrl!);
8686
}
8787

88+
8889
[HttpGet("oauth2/token")]
8990
public async Task<IActionResult> GetOAuth2Token([FromQuery] string state)
9091
{

ProjectVG.Application/ApplicationServiceCollectionExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public static class ApplicationServiceCollectionExtensions
2020
public static IServiceCollection AddApplicationServices(this IServiceCollection services)
2121
{
2222
// Auth Services
23-
services.AddScoped<IAuthService, AuthService>();
23+
services.AddScoped<IUserAuthService, AuthService>();
2424
services.AddScoped<IOAuth2Service, OAuth2Service>();
2525
services.AddScoped<IOAuth2ProviderFactory, OAuth2ProviderFactory>();
2626

Lines changed: 94 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,25 @@
11
using Microsoft.Extensions.Logging;
2+
using ProjectVG.Application.Models.Auth;
23
using ProjectVG.Application.Models.User;
3-
using ProjectVG.Application.Services.Users;
44
using ProjectVG.Application.Services.Credit;
5-
using ProjectVG.Infrastructure.Auth;
6-
using ProjectVG.Common.Exceptions;
5+
using ProjectVG.Application.Services.Users;
76
using ProjectVG.Common.Constants;
7+
using ProjectVG.Common.Exceptions;
88
using ProjectVG.Domain.Entities.Users;
9+
using ProjectVG.Infrastructure.Auth;
10+
using System;
911

1012
namespace ProjectVG.Application.Services.Auth
1113
{
12-
public class AuthService : IAuthService
14+
public class AuthService : IUserAuthService
1315
{
1416
private readonly IUserService _userService;
1517
private readonly ITokenService _tokenService;
1618
private readonly ICreditManagementService _tokenManagementService;
1719
private readonly ILogger<AuthService> _logger;
1820

1921
public AuthService(
20-
IUserService userService,
22+
IUserService userService,
2123
ITokenService tokenService,
2224
ICreditManagementService tokenManagementService,
2325
ILogger<AuthService> logger)
@@ -28,142 +30,143 @@ public AuthService(
2830
_logger = logger;
2931
}
3032

31-
public async Task<AuthResult> LoginWithOAuthAsync(string provider, string providerUserId)
33+
public async Task<AuthResult> SignInWithOAuthAsync(string provider, string providerUserId)
3234
{
33-
// OAuth 프로바이더별 사용자 처리
34-
Guid userId;
35-
UserDto user;
36-
37-
if (provider == "guest")
38-
{
39-
if (string.IsNullOrEmpty(providerUserId))
40-
{
41-
throw new ValidationException(ErrorCode.GUEST_ID_INVALID);
42-
}
43-
44-
// 기존 게스트 사용자가 있는지 확인
45-
user = await _userService.TryGetByProviderAsync("guest", providerUserId);
46-
47-
if (user == null)
48-
{
49-
// 새로운 게스트 사용자 생성
50-
string uuid = GenerateGuestUuid(providerUserId);
51-
var createCommand = new UserCreateCommand(
52-
Username: $"guest_{uuid}",
53-
Email: $"guest@guest{uuid}.local",
54-
ProviderId: providerUserId,
55-
Provider: "guest"
56-
);
57-
58-
user = await _userService.CreateUserAsync(createCommand);
59-
_logger.LogInformation("New guest user created: {UserId} with GuestId: {GuestId}", user.Id, providerUserId);
60-
}
61-
else
62-
{
63-
_logger.LogInformation("Existing guest user logged in: {UserId} with GuestId: {GuestId}", user.Id, providerUserId);
64-
}
35+
return provider switch {
36+
"guest" => await GuestLoginAsync(providerUserId),
37+
"google" or "apple" => await OAuth2LoginAsync(provider, providerUserId),
38+
_ => throw new ValidationException(ErrorCode.OAUTH2_PROVIDER_NOT_SUPPORTED)
39+
};
40+
}
41+
42+
private async Task<AuthResult> GuestLoginAsync(string guestId)
43+
{
44+
if (string.IsNullOrEmpty(guestId)) {
45+
throw new ValidationException(ErrorCode.GUEST_ID_INVALID);
6546
}
66-
// 실제 OAuth 프로바이더인 경우 (Google, Apple 등)
67-
else if (provider == "google" || provider == "apple")
68-
{
69-
if (string.IsNullOrEmpty(providerUserId))
70-
{
71-
throw new ValidationException(ErrorCode.PROVIDER_USER_ID_INVALID);
72-
}
73-
74-
// 새로운 사용자 ID 생성
75-
userId = Guid.NewGuid();
76-
77-
user = new UserDto
78-
{
79-
Id = userId,
80-
Username = $"{provider}_user_{providerUserId}",
81-
Email = $"{providerUserId}@{provider}.oauth",
82-
Status = AccountStatus.Active
83-
};
8447

85-
_logger.LogInformation("New OAuth user created: {UserId} from {Provider} with ProviderId: {ProviderId}",
86-
userId, provider, providerUserId);
48+
var user = await _userService.TryGetByProviderAsync("guest", guestId);
49+
50+
if (user == null) {
51+
string uuid = GenerateGuestUuid(guestId);
52+
var createCommand = new UserCreateCommand(
53+
Username: $"guest_{uuid}",
54+
Email: $"guest@guest{uuid}.local",
55+
ProviderId: guestId,
56+
Provider: "guest"
57+
);
58+
59+
user = await _userService.CreateUserAsync(createCommand);
60+
_logger.LogInformation("새 게스트 사용자 생성됨: UserId={UserId}, GuestId={GuestId}", user.Id, guestId);
61+
}
62+
else {
63+
_logger.LogDebug("기존 게스트 사용자 로그인: UserId={UserId}, GuestId={GuestId}", user.Id, guestId);
8764
}
88-
else
89-
{
90-
throw new ValidationException(ErrorCode.OAUTH2_PROVIDER_NOT_SUPPORTED);
65+
66+
return await FinalizeLoginAsync(user, "guest");
67+
}
68+
69+
private async Task<AuthResult> OAuth2LoginAsync(string provider, string providerUserId)
70+
{
71+
if (string.IsNullOrEmpty(providerUserId)) {
72+
throw new ValidationException(ErrorCode.PROVIDER_USER_ID_INVALID);
9173
}
9274

93-
// OAuth2 사용자인 경우 Provider 정보를 포함하여 사용자 생성 (test와 guest는 이미 처리됨)
94-
if (provider != "test" && provider != "guest")
95-
{
96-
user = user with { Provider = provider, ProviderId = providerUserId };
75+
var user = await _userService.TryGetByProviderAsync(provider, providerUserId);
76+
77+
if (user == null) {
78+
string uuid = GenerateGuestUuid(providerUserId);
79+
var createCommand = new UserCreateCommand(
80+
Username: $"임시 유저 이름",
81+
Email: $"guest@guest{uuid}.local",
82+
ProviderId: providerUserId,
83+
Provider: provider
84+
);
85+
86+
87+
user = new UserDto {
88+
89+
90+
Id = Guid.NewGuid(),
91+
Username = $"{provider}_user_{providerUserId}",
92+
Email = $"{providerUserId}@{provider}.oauth",
93+
Status = AccountStatus.Active,
94+
Provider = provider,
95+
ProviderId = providerUserId
96+
};
9797
}
9898

99-
// 첫 로그인 토큰 지급 시도
99+
_logger.LogInformation("새 OAuth 사용자 생성됨: UserId={UserId}, Provider={Provider}, ProviderId={ProviderId}",
100+
user.Id, provider, providerUserId);
101+
102+
return await FinalizeLoginAsync(user, provider);
103+
}
104+
105+
private async Task<AuthResult> FinalizeLoginAsync(UserDto user, string provider)
106+
{
107+
// 초기 크레딧 지급
100108
var tokenGranted = await _tokenManagementService.GrantInitialCreditsAsync(user.Id);
101-
if (tokenGranted)
102-
{
103-
_logger.LogInformation("Initial tokens (5000) granted successfully to user {UserId}", user.Id);
109+
if (tokenGranted) {
110+
_logger.LogInformation("사용자 {UserId}에게 최초 크레딧 지급 완료", user.Id);
104111
}
105-
else
106-
{
107-
_logger.LogInformation("Initial tokens already granted or grant failed for user {UserId}", user.Id);
112+
else {
113+
_logger.LogDebug("사용자 {UserId}는 이미 크레딧이 지급되었거나 지급 실패", user.Id);
108114
}
109115

116+
// 최종 JWT 토큰 발급
110117
var tokens = await _tokenService.GenerateTokensAsync(user.Id);
111-
112-
_logger.LogInformation("Users {UserId} logged in with OAuth provider: {Provider}", user.Id, provider);
113-
114-
return new AuthResult
115-
{
118+
119+
_logger.LogDebug("사용자 {UserId} 로그인 완료 (Provider={Provider})", user.Id, provider);
120+
121+
return new AuthResult {
116122
Tokens = tokens,
117123
User = user
118124
};
119125
}
120126

121-
public async Task<AuthResult> RefreshTokenAsync(string refreshToken)
127+
public async Task<AuthResult> RefreshAccessTokenAsync(string? refreshToken)
122128
{
123-
if (string.IsNullOrEmpty(refreshToken))
124-
{
129+
if (string.IsNullOrEmpty(refreshToken)) {
125130
throw new ValidationException(ErrorCode.TOKEN_MISSING, "리프레시 토큰이 필요합니다");
126131
}
127132

128133
var tokens = await _tokenService.RefreshAccessTokenAsync(refreshToken);
129-
if (tokens == null)
130-
{
134+
if (tokens == null) {
131135
throw new ValidationException(ErrorCode.TOKEN_REFRESH_FAILED, "유효하지 않거나 만료된 리프레시 토큰입니다");
132136
}
133137

134138
var userId = await _tokenService.GetUserIdFromTokenAsync(refreshToken);
135139
var user = userId.HasValue ? await _userService.TryGetByIdAsync(userId.Value) : null;
136140

137-
return new AuthResult
138-
{
141+
return new AuthResult {
139142
Tokens = tokens,
140143
User = user
141144
};
142145
}
143146

144147
public async Task<bool> LogoutAsync(string refreshToken)
145148
{
146-
if (string.IsNullOrEmpty(refreshToken))
147-
{
149+
if (string.IsNullOrEmpty(refreshToken)) {
148150
throw new ValidationException(ErrorCode.TOKEN_MISSING, "리프레시 토큰이 필요합니다");
149151
}
150152

151153
var revoked = await _tokenService.RevokeRefreshTokenAsync(refreshToken);
152-
if (revoked)
153-
{
154+
if (revoked) {
154155
var userId = await _tokenService.GetUserIdFromTokenAsync(refreshToken);
155-
_logger.LogInformation("Users {UserId} logged out successfully", userId);
156+
_logger.LogInformation("사용자 {UserId} 로그아웃 성공", userId);
157+
}
158+
else {
159+
_logger.LogWarning("리프레시 토큰 만료 또는 무효화 실패: {RefreshToken}", refreshToken);
156160
}
157161
return revoked;
158162
}
159-
160163
private static string GenerateGuestUuid(string providerUserId)
161164
{
162-
// SHA256 해시를 사용하여 일관된 UUID 생성
163165
using var sha256 = System.Security.Cryptography.SHA256.Create();
164166
var hash = sha256.ComputeHash(System.Text.Encoding.UTF8.GetBytes(providerUserId));
165167
var hashString = Convert.ToHexString(hash);
166168
return hashString.Substring(0, Math.Min(hashString.Length, 16)).ToLowerInvariant();
167169
}
170+
168171
}
169172
}

ProjectVG.Application/Services/Auth/IAuthService.cs renamed to ProjectVG.Application/Services/Auth/IUserAuthService.cs

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,28 +7,21 @@ namespace ProjectVG.Application.Services.Auth
77
/// 인증 및 토큰 관리 서비스
88
/// JWT 토큰 생성, 검증, 갱신 및 OAuth 로그인 처리를 담당
99
/// </summary>
10-
public interface IAuthService
10+
public interface IUserAuthService
1111
{
1212
/// <summary>
13-
/// OAuth 제공자를 통한 로그인 처리 (Google, GitHub, Microsoft, 게스트 등)
13+
/// OAuth 제공자를 통한 로그인 처리
1414
/// </summary>
15-
/// <param name="provider">인증 제공자 (google, github, microsoft, guest, test)</param>
16-
/// <param name="providerUserId">제공자별 사용자 ID</param>
17-
/// <returns>로그인 결과 (토큰, 사용자 정보 포함)</returns>
18-
Task<AuthResult> LoginWithOAuthAsync(string provider, string providerUserId);
15+
Task<AuthResult> SignInWithOAuthAsync(string provider, string providerUserId);
1916

2017
/// <summary>
2118
/// 리프레시 토큰을 사용하여 새로운 액세스 토큰 발급
2219
/// </summary>
23-
/// <param name="refreshToken">유효한 리프레시 토큰</param>
24-
/// <returns>새로운 토큰 쌍과 사용자 정보</returns>
25-
Task<AuthResult> RefreshTokenAsync(string? refreshToken);
20+
Task<AuthResult> RefreshAccessTokenAsync(string? refreshToken);
2621

2722
/// <summary>
2823
/// 사용자 로그아웃 처리 (리프레시 토큰 무효화)
2924
/// </summary>
30-
/// <param name="refreshToken">무효화할 리프레시 토큰</param>
31-
/// <returns>로그아웃 성공 여부</returns>
3225
Task<bool> LogoutAsync(string? refreshToken);
3326
}
3427

0 commit comments

Comments
 (0)