Skip to content

Commit 0045e00

Browse files
authored
Merge pull request #2 from ProjectVG/refactory/refactoring-server
Refactory: 전체적인 서버 코드 리팩토링
2 parents cf3734f + 69978d5 commit 0045e00

File tree

155 files changed

+4150
-3671
lines changed

Some content is hidden

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

155 files changed

+4150
-3671
lines changed
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
using Microsoft.AspNetCore.Builder;
2+
using ProjectVG.Api.Middleware;
3+
using ProjectVG.Api.Services;
4+
5+
namespace ProjectVG.Api
6+
{
7+
public static class ApiMiddlewareExtensions
8+
{
9+
/// <summary>
10+
/// API 미들웨어 파이프라인 구성
11+
/// </summary>
12+
public static IApplicationBuilder UseApiMiddleware(this IApplicationBuilder app, IWebHostEnvironment environment)
13+
{
14+
// 개발 환경 설정
15+
if (environment.IsDevelopment()) {
16+
app.UseSwagger();
17+
app.UseSwaggerUI(c => {
18+
c.SwaggerEndpoint("/swagger/v1/swagger.json", "ProjectVG API V1");
19+
c.RoutePrefix = "swagger";
20+
});
21+
}
22+
23+
// 전역 예외 처리
24+
app.UseGlobalExceptionHandler();
25+
26+
// WebSocket 지원
27+
app.UseWebSockets();
28+
29+
// WebSocket 미들웨어 등록
30+
app.UseMiddleware<WebSocketMiddleware>();
31+
32+
// 요청 로깅 미들웨어
33+
app.Use(async (ctx, next) => {
34+
var logger = ctx.RequestServices.GetRequiredService<ILogger<Program>>();
35+
logger.LogInformation("REQ {method} {path} from {remote}", ctx.Request.Method, ctx.Request.Path, ctx.Connection.RemoteIpAddress);
36+
await next();
37+
});
38+
39+
// 인증/인가
40+
app.UseAuthentication();
41+
app.UseAuthorization();
42+
43+
// CORS 미들웨어 적용
44+
app.UseCors("AllowAll");
45+
46+
// 컨트롤러 매핑
47+
app.UseRouting();
48+
app.UseEndpoints(endpoints => {
49+
endpoints.MapControllers();
50+
});
51+
52+
return app;
53+
}
54+
55+
/// <summary>
56+
/// 개발 환경 전용 기능
57+
/// </summary>
58+
public static IApplicationBuilder UseDevelopmentFeatures(this IApplicationBuilder app)
59+
{
60+
// 개발 환경에서 테스트 클라이언트 자동 실행
61+
var serviceProvider = app.ApplicationServices;
62+
serviceProvider.GetRequiredService<TestClientLauncher>().Launch();
63+
64+
return app;
65+
}
66+
}
67+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
using Microsoft.Extensions.DependencyInjection;
2+
using ProjectVG.Api.Services;
3+
using ProjectVG.Api.Filters;
4+
using Microsoft.AspNetCore.Authentication.Negotiate;
5+
6+
namespace ProjectVG.Api
7+
{
8+
public static class ApiServiceCollectionExtensions
9+
{
10+
/// <summary>
11+
/// API 서비스 등록
12+
/// </summary>
13+
public static IServiceCollection AddApiServices(this IServiceCollection services)
14+
{
15+
services.AddControllers(options => {
16+
options.Filters.Add<ModelStateValidationFilter>();
17+
});
18+
19+
services.AddEndpointsApiExplorer();
20+
services.AddSwaggerGen(c => {
21+
c.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo {
22+
Title = "ProjectVG API",
23+
Version = "v1",
24+
Description = "ProjectVG API Server"
25+
});
26+
});
27+
28+
services.AddSingleton<TestClientLauncher>();
29+
30+
return services;
31+
}
32+
33+
/// <summary>
34+
/// 인증 및 인가 서비스
35+
/// </summary>
36+
public static IServiceCollection AddApiAuthentication(this IServiceCollection services)
37+
{
38+
services.AddAuthentication(NegotiateDefaults.AuthenticationScheme)
39+
.AddNegotiate();
40+
41+
services.AddAuthorization(options => {
42+
options.FallbackPolicy = null;
43+
});
44+
45+
return services;
46+
}
47+
48+
/// <summary>
49+
/// 개발용 CORS 정책
50+
/// </summary>
51+
public static IServiceCollection AddDevelopmentCors(this IServiceCollection services)
52+
{
53+
services.AddCors(options => {
54+
options.AddPolicy("AllowAll",
55+
policy => policy.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());
56+
});
57+
58+
return services;
59+
}
60+
}
61+
}

ProjectVG.Api/Configuration/EnvironmentVariableConfigurationProvider.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,15 @@ public EnvironmentVariableConfigurationProvider(IConfiguration configuration)
1414

1515
public override void Load()
1616
{
17-
var data = new Dictionary<string, string>();
17+
var data = new Dictionary<string, string?>();
1818

1919
// 모든 설정을 순회하면서 환경 변수 참조를 찾아서 치환
2020
ReplaceEnvironmentVariables(_configuration, data, "");
2121

2222
Data = data;
2323
}
2424

25-
private void ReplaceEnvironmentVariables(IConfiguration configuration, Dictionary<string, string> data, string prefix)
25+
private void ReplaceEnvironmentVariables(IConfiguration configuration, Dictionary<string, string?> data, string prefix)
2626
{
2727
foreach (var child in configuration.GetChildren())
2828
{
Lines changed: 40 additions & 168 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
using Microsoft.AspNetCore.Mvc;
22
using ProjectVG.Application.Services.User;
33
using ProjectVG.Application.Models.User;
4-
using Microsoft.Extensions.Logging;
4+
using ProjectVG.Api.Models.Auth.Request;
5+
using ProjectVG.Api.Models.Auth.Response;
56

67
namespace ProjectVG.Api.Controllers
78
{
@@ -18,191 +19,62 @@ public AuthController(IUserService userService, ILogger<AuthController> logger)
1819
_logger = logger;
1920
}
2021

21-
/// <summary>
22-
/// 회원가입
23-
/// </summary>
2422
[HttpPost("register")]
25-
public async Task<ActionResult<AuthResponseDto>> Register([FromBody] RegisterRequestDto request)
23+
public async Task<ActionResult<AuthResponse>> Register([FromBody] RegisterRequest request)
2624
{
27-
try
25+
var userDto = request.ToUserDto();
26+
var createdUser = await _userService.CreateUserAsync(userDto);
27+
28+
var response = new AuthResponse
2829
{
29-
if (!ModelState.IsValid)
30-
{
31-
return BadRequest(ModelState);
32-
}
33-
34-
var userDto = new UserDto
35-
{
36-
Username = request.Username,
37-
Name = request.Name,
38-
Email = request.Email,
39-
Provider = "local",
40-
ProviderId = request.Username,
41-
IsActive = true
42-
};
43-
44-
var createdUser = await _userService.CreateUserAsync(userDto);
45-
46-
var response = new AuthResponseDto
47-
{
48-
Success = true,
49-
Message = "회원가입이 완료되었습니다.",
50-
UserId = createdUser.Id,
51-
Username = createdUser.Username,
52-
Email = createdUser.Email
53-
};
54-
55-
_logger.LogInformation("새 사용자 회원가입 완료: {Username}", createdUser.Username);
56-
return Ok(response);
57-
}
58-
catch (InvalidOperationException ex)
59-
{
60-
return BadRequest(new AuthResponseDto
61-
{
62-
Success = false,
63-
Message = ex.Message
64-
});
65-
}
66-
catch (Exception ex)
67-
{
68-
_logger.LogError(ex, "회원가입 중 오류가 발생했습니다");
69-
return StatusCode(500, new AuthResponseDto
70-
{
71-
Success = false,
72-
Message = "회원가입 중 내부 서버 오류가 발생했습니다."
73-
});
74-
}
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);
7539
}
7640

77-
/// <summary>
78-
/// 로그인
79-
/// </summary>
8041
[HttpPost("login")]
81-
public async Task<ActionResult<AuthResponseDto>> Login([FromBody] LoginRequestDto request)
42+
public async Task<ActionResult<AuthResponse>> Login([FromBody] LoginRequest request)
8243
{
83-
try
84-
{
85-
if (!ModelState.IsValid)
86-
{
87-
return BadRequest(ModelState);
88-
}
89-
90-
// 사용자명으로 사용자 조회
91-
var user = await _userService.GetUserByUsernameAsync(request.Username);
92-
if (user == null)
93-
{
94-
return Unauthorized(new AuthResponseDto
95-
{
96-
Success = false,
97-
Message = "사용자명 또는 비밀번호가 올바르지 않습니다."
98-
});
99-
}
100-
101-
// TODO: 실제 비밀번호 검증 로직 추가 필요
102-
103-
var response = new AuthResponseDto
104-
{
105-
Success = true,
106-
Message = "로그인이 완료되었습니다.",
107-
UserId = user.Id,
108-
Username = user.Username,
109-
Email = user.Email
110-
};
111-
112-
_logger.LogInformation("사용자 로그인 완료: {Username}", user.Username);
113-
return Ok(response);
114-
}
115-
catch (Exception ex)
44+
var user = await _userService.GetUserByUsernameAsync(request.Username);
45+
var response = new AuthResponse
11646
{
117-
_logger.LogError(ex, "로그인 중 오류가 발생했습니다");
118-
return StatusCode(500, new AuthResponseDto
119-
{
120-
Success = false,
121-
Message = "로그인 중 내부 서버 오류가 발생했습니다."
122-
});
123-
}
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);
12456
}
12557

126-
/// <summary>
127-
/// 사용자명 중복 확인
128-
/// </summary>
12958
[HttpGet("check-username/{username}")]
130-
public async Task<ActionResult<CheckResponseDto>> CheckUsername(string username)
59+
public async Task<ActionResult<CheckResponse>> CheckUsername(string username)
13160
{
132-
try
133-
{
134-
var exists = await _userService.UsernameExistsAsync(username);
135-
return Ok(new CheckResponseDto
136-
{
137-
Exists = exists,
138-
Message = exists ? "이미 사용 중인 사용자명입니다." : "사용 가능한 사용자명입니다."
139-
});
140-
}
141-
catch (Exception ex)
61+
var exists = await _userService.UsernameExistsAsync(username);
62+
return Ok(new CheckResponse
14263
{
143-
_logger.LogError(ex, "사용자명 중복 확인 중 오류가 발생했습니다");
144-
return StatusCode(500, new CheckResponseDto
145-
{
146-
Exists = false,
147-
Message = "중복 확인 중 내부 서버 오류가 발생했습니다."
148-
});
149-
}
64+
Exists = exists,
65+
Message = exists ? "이미 사용 중인 사용자명입니다." : "사용 가능한 사용자명입니다."
66+
});
15067
}
15168

152-
/// <summary>
153-
/// 이메일 중복 확인
154-
/// </summary>
15569
[HttpGet("check-email/{email}")]
156-
public async Task<ActionResult<CheckResponseDto>> CheckEmail(string email)
70+
public async Task<ActionResult<CheckResponse>> CheckEmail(string email)
15771
{
158-
try
159-
{
160-
var exists = await _userService.EmailExistsAsync(email);
161-
return Ok(new CheckResponseDto
162-
{
163-
Exists = exists,
164-
Message = exists ? "이미 사용 중인 이메일입니다." : "사용 가능한 이메일입니다."
165-
});
166-
}
167-
catch (Exception ex)
72+
var exists = await _userService.EmailExistsAsync(email);
73+
return Ok(new CheckResponse
16874
{
169-
_logger.LogError(ex, "이메일 중복 확인 중 오류가 발생했습니다");
170-
return StatusCode(500, new CheckResponseDto
171-
{
172-
Exists = false,
173-
Message = "중복 확인 중 내부 서버 오류가 발생했습니다."
174-
});
175-
}
75+
Exists = exists,
76+
Message = exists ? "이미 사용 중인 이메일입니다." : "사용 가능한 이메일입니다."
77+
});
17678
}
17779
}
178-
179-
// DTO 클래스들
180-
public class RegisterRequestDto
181-
{
182-
public string Username { get; set; } = string.Empty;
183-
public string Name { get; set; } = string.Empty;
184-
public string Email { get; set; } = string.Empty;
185-
public string Password { get; set; } = string.Empty;
186-
}
187-
188-
public class LoginRequestDto
189-
{
190-
public string Username { get; set; } = string.Empty;
191-
public string Password { get; set; } = string.Empty;
192-
}
193-
194-
public class AuthResponseDto
195-
{
196-
public bool Success { get; set; }
197-
public string Message { get; set; } = string.Empty;
198-
public Guid? UserId { get; set; }
199-
public string? Username { get; set; }
200-
public string? Email { get; set; }
201-
}
202-
203-
public class CheckResponseDto
204-
{
205-
public bool Exists { get; set; }
206-
public string Message { get; set; } = string.Empty;
207-
}
20880
}

0 commit comments

Comments
 (0)