Skip to content

Commit 22acc5f

Browse files
authored
Merge pull request #5 from ProjectVG/feature/auth
Feature/auth
2 parents 0045e00 + ec8239f commit 22acc5f

File tree

143 files changed

+11227
-1715
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

143 files changed

+11227
-1715
lines changed

.dockerignore

Lines changed: 82 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,82 @@
1-
**/.classpath
2-
**/.dockerignore
3-
**/.env
4-
**/.git
5-
**/.gitignore
6-
**/.project
7-
**/.settings
8-
**/.toolstarget
9-
**/.vs
10-
**/.vscode
11-
**/*.*proj.user
12-
**/*.dbmdl
13-
**/*.jfm
14-
**/azds.yaml
15-
**/bin
16-
**/charts
17-
**/docker-compose*
18-
**/Dockerfile*
19-
**/node_modules
20-
**/npm-debug.log
21-
**/obj
22-
**/secrets.dev.yaml
23-
**/values.dev.yaml
24-
LICENSE
25-
README.md
26-
!**/.gitignore
27-
!.git/HEAD
28-
!.git/config
29-
!.git/packed-refs
30-
!.git/refs/heads/**
1+
# Git 관련
2+
.git
3+
.gitignore
4+
.gitattributes
5+
6+
# IDE 관련
7+
.vs/
8+
.vscode/
9+
*.user
10+
*.suo
11+
*.userosscache
12+
*.sln.docstates
13+
14+
# Build 결과물
15+
bin/
16+
obj/
17+
[Dd]ebug/
18+
[Rr]elease/
19+
x64/
20+
x86/
21+
[Aa][Rr][Mm]/
22+
[Aa][Rr][Mm]64/
23+
bld/
24+
[Bb]in/
25+
[Oo]bj/
26+
[Ll]og/
27+
[Ll]ogs/
28+
29+
# NuGet 관련
30+
*.nupkg
31+
*.snupkg
32+
**/[Pp]ackages/*
33+
!**/[Pp]ackages/build/
34+
*.nuget.props
35+
*.nuget.targets
36+
37+
# 테스트 관련
38+
**/*[Tt]ests/
39+
**/*[Tt]est/
40+
**/*.Tests/
41+
**/*.Test/
42+
coverage/
43+
*.coverage
44+
*.coveragexml
45+
46+
# 문서
47+
docs/
48+
*.md
49+
README*
50+
51+
# 스크립트
52+
scripts/
53+
*.ps1
54+
*.sh
55+
56+
# Docker 관련
57+
Dockerfile*
58+
docker-compose*
59+
.dockerignore
60+
61+
# 환경 변수
62+
.env
63+
.env.local
64+
.env.development
65+
.env.production
66+
67+
# 임시 파일
68+
*.tmp
69+
*.temp
70+
*.log
71+
*.bak
72+
*.swp
73+
*.swo
74+
*~
75+
76+
# OS 관련
77+
.DS_Store
78+
Thumbs.db
79+
80+
# 프로젝트 특정
81+
test-clients/
82+
mssql_data/

.gitignore

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,15 @@ publish/
123123
# VS auto-generated
124124
Generated_Code/
125125

126+
# Claude AI related files
127+
CLAUDE.md
128+
claude.md
129+
*CLAUDE.md
130+
*claude.md
131+
.claude/
132+
claude-*
133+
*claude*
134+
126135
# Secrets (if using secrets.json for config)
127136
secrets.json
128137

ProjectVG.Api/ApiServiceCollectionExtensions.cs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
using ProjectVG.Api.Services;
33
using ProjectVG.Api.Filters;
44
using Microsoft.AspNetCore.Authentication.Negotiate;
5+
using Microsoft.AspNetCore.Authentication.Cookies;
6+
using Microsoft.IdentityModel.Tokens;
57

68
namespace ProjectVG.Api
79
{
@@ -45,14 +47,30 @@ public static IServiceCollection AddApiAuthentication(this IServiceCollection se
4547
return services;
4648
}
4749

50+
/// <summary>
51+
/// OAuth2 인증 서비스 (선택적)
52+
/// </summary>
53+
public static IServiceCollection AddOAuth2Authentication(this IServiceCollection services)
54+
{
55+
// OAuth2는 별도 컨트롤러에서 처리하므로 기본 인증만 설정
56+
services.AddAuthentication(options =>
57+
{
58+
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
59+
})
60+
.AddCookie();
61+
62+
return services;
63+
}
64+
4865
/// <summary>
4966
/// 개발용 CORS 정책
5067
/// </summary>
5168
public static IServiceCollection AddDevelopmentCors(this IServiceCollection services)
5269
{
5370
services.AddCors(options => {
5471
options.AddPolicy("AllowAll",
55-
policy => policy.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());
72+
policy => policy.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader()
73+
.WithExposedHeaders("X-Access-Token", "X-Refresh-Token", "X-Expires-In", "X-UID"));
5674
});
5775

5876
return services;
Lines changed: 37 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,80 +1,67 @@
11
using Microsoft.AspNetCore.Mvc;
2-
using ProjectVG.Application.Services.User;
3-
using ProjectVG.Application.Models.User;
4-
using ProjectVG.Api.Models.Auth.Request;
5-
using ProjectVG.Api.Models.Auth.Response;
2+
using ProjectVG.Application.Services.Auth;
63

74
namespace ProjectVG.Api.Controllers
85
{
96
[ApiController]
107
[Route("api/v1/[controller]")]
118
public class AuthController : ControllerBase
129
{
13-
private readonly IUserService _userService;
14-
private readonly ILogger<AuthController> _logger;
10+
private readonly IAuthService _authService;
1511

16-
public AuthController(IUserService userService, ILogger<AuthController> logger)
12+
public AuthController(IAuthService authService)
1713
{
18-
_userService = userService;
19-
_logger = logger;
14+
_authService = authService;
2015
}
2116

22-
[HttpPost("register")]
23-
public async Task<ActionResult<AuthResponse>> Register([FromBody] RegisterRequest request)
17+
[HttpPost("refresh")]
18+
public async Task<IActionResult> RefreshToken()
2419
{
25-
var userDto = request.ToUserDto();
26-
var createdUser = await _userService.CreateUserAsync(userDto);
20+
var refreshToken = GetRefreshTokenFromHeader();
21+
var result = await _authService.RefreshTokenAsync(refreshToken);
2722

28-
var response = new AuthResponse
23+
return Ok(new
2924
{
30-
Success = true,
31-
Message = "회원가입이 완료되었습니다.",
32-
UserId = createdUser.Id,
33-
Username = createdUser.Username,
34-
Email = createdUser.Email
35-
};
36-
37-
_logger.LogInformation("새 사용자 회원가입 완료: {Username}", createdUser.Username);
38-
return Ok(response);
25+
success = true,
26+
tokens = result.Tokens,
27+
user = result.User
28+
});
3929
}
4030

41-
[HttpPost("login")]
42-
public async Task<ActionResult<AuthResponse>> Login([FromBody] LoginRequest request)
31+
[HttpPost("logout")]
32+
public async Task<IActionResult> Logout()
4333
{
44-
var user = await _userService.GetUserByUsernameAsync(request.Username);
45-
var response = new AuthResponse
34+
var refreshToken = GetRefreshTokenFromHeader();
35+
var success = await _authService.LogoutAsync(refreshToken);
36+
37+
return Ok(new
4638
{
47-
Success = true,
48-
Message = "로그인이 완료되었습니다.",
49-
UserId = user.Id,
50-
Username = user.Username,
51-
Email = user.Email
52-
};
53-
54-
_logger.LogInformation("사용자 로그인 완료: {Username}", user.Username);
55-
return Ok(response);
39+
success = success,
40+
message = success ? "Logout successful" : "Logout failed"
41+
});
5642
}
5743

58-
[HttpGet("check-username/{username}")]
59-
public async Task<ActionResult<CheckResponse>> CheckUsername(string username)
44+
[HttpPost("guest-login")]
45+
public async Task<IActionResult> GuestLogin([FromBody] string guestId)
6046
{
61-
var exists = await _userService.UsernameExistsAsync(username);
62-
return Ok(new CheckResponse
47+
if (string.IsNullOrEmpty(guestId))
6348
{
64-
Exists = exists,
65-
Message = exists ? "이미 사용 중인 사용자명입니다." : "사용 가능한 사용자명입니다."
49+
throw new ValidationException(ErrorCode.GUEST_ID_INVALID);
50+
}
51+
52+
var result = await _authService.LoginWithOAuthAsync("guest", guestId);
53+
54+
return Ok(new
55+
{
56+
success = true,
57+
tokens = result.Tokens,
58+
user = result.User
6659
});
6760
}
6861

69-
[HttpGet("check-email/{email}")]
70-
public async Task<ActionResult<CheckResponse>> CheckEmail(string email)
62+
private string GetRefreshTokenFromHeader()
7163
{
72-
var exists = await _userService.EmailExistsAsync(email);
73-
return Ok(new CheckResponse
74-
{
75-
Exists = exists,
76-
Message = exists ? "이미 사용 중인 이메일입니다." : "사용 가능한 이메일입니다."
77-
});
64+
return Request.Headers["X-Refresh-Token"].FirstOrDefault() ?? string.Empty;
7865
}
7966
}
8067
}
Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,43 @@
1-
using ProjectVG.Application.Models.API.Request;
2-
using ProjectVG.Application.Services.Chat;
31
using Microsoft.AspNetCore.Mvc;
42
using Microsoft.AspNetCore.Authorization;
3+
using ProjectVG.Application.Models.Chat;
4+
using ProjectVG.Application.Models.API.Request;
5+
using ProjectVG.Application.Services.Chat;
6+
using System.Security.Claims;
57

68
namespace ProjectVG.Api.Controllers
79
{
810
[ApiController]
911
[Route("api/v1/chat")]
10-
[AllowAnonymous]
1112
public class ChatController : ControllerBase
1213
{
1314
private readonly IChatService _chatService;
14-
private readonly IServiceScopeFactory _scopeFactory;
15-
private readonly ILogger<ChatController> _logger;
1615

17-
public ChatController(IChatService chatService, IServiceScopeFactory scopeFactory, ILogger<ChatController> logger)
16+
public ChatController(IChatService chatService)
1817
{
1918
_chatService = chatService;
20-
_scopeFactory = scopeFactory;
21-
_logger = logger;
2219
}
2320

2421
[HttpPost]
22+
[JwtAuthentication]
2523
public async Task<IActionResult> ProcessChat([FromBody] ChatRequest request)
2624
{
27-
var command = request.ToProcessChatCommand();
28-
var requestResponse = await _chatService.EnqueueChatRequestAsync(command);
25+
var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
26+
if (string.IsNullOrEmpty(userId) || !Guid.TryParse(userId, out var userGuid))
27+
{
28+
throw new ValidationException(ErrorCode.AUTHENTICATION_FAILED);
29+
}
30+
31+
var command = new ProcessChatCommand
32+
{
33+
UserId = userGuid,
34+
Message = request.Message,
35+
CharacterId = request.CharacterId
36+
};
2937

30-
return Ok(new {
31-
success = true,
32-
status = requestResponse.Status,
33-
message = requestResponse.Message,
34-
sessionId = requestResponse.SessionId,
35-
userId = requestResponse.UserId,
36-
characterId = requestResponse.CharacterId,
37-
requestedAt = requestResponse.RequestedAt
38-
});
38+
var result = await _chatService.EnqueueChatRequestAsync(command);
39+
40+
return Ok(result);
3941
}
4042
}
4143
}

0 commit comments

Comments
 (0)