Skip to content

Commit ad73933

Browse files
authored
Merge pull request #6 from ProjectVG/coderabbitai/docstrings/ec8239f
๐Ÿ“ Add docstrings to `feature/auth`
2 parents ec8239f + a527343 commit ad73933

File tree

78 files changed

+1967
-110
lines changed

Some content is hidden

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

78 files changed

+1967
-110
lines changed

โ€ŽProjectVG.Api/ApiServiceCollectionExtensions.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,10 @@ public static IServiceCollection AddApiServices(this IServiceCollection services
3434

3535
/// <summary>
3636
/// ์ธ์ฆ ๋ฐ ์ธ๊ฐ€ ์„œ๋น„์Šค
37+
/// <summary>
38+
/// Negotiate(Windows) ์ธ์ฆ ์Šคํ‚ด์„ ์ถ”๊ฐ€ํ•˜๊ณ  ์ „์—ญ ๋Œ€์ฒด ๊ถŒํ•œ ์ •์ฑ…(FallbackPolicy)์„ ์ œ๊ฑฐํ•˜์—ฌ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ธ์ฆ/์ธ๊ฐ€๋ฅผ ๊ตฌ์„ฑํ•ฉ๋‹ˆ๋‹ค.
3739
/// </summary>
40+
/// <returns>๊ตฌ์„ฑ๋œ IServiceCollection ์ธ์Šคํ„ด์Šค.</returns>
3841
public static IServiceCollection AddApiAuthentication(this IServiceCollection services)
3942
{
4043
services.AddAuthentication(NegotiateDefaults.AuthenticationScheme)
@@ -49,7 +52,10 @@ public static IServiceCollection AddApiAuthentication(this IServiceCollection se
4952

5053
/// <summary>
5154
/// OAuth2 ์ธ์ฆ ์„œ๋น„์Šค (์„ ํƒ์ )
55+
/// <summary>
56+
/// ์ฟ ํ‚ค ์ธ์ฆ์„ ๊ธฐ๋ณธ ์ธ์ฆ ๋ฐฉ์‹์œผ๋กœ ์„ค์ •ํ•˜์—ฌ OAuth2 ํ๋ฆ„์„ ๋ณ„๋„ ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ตฌ์„ฑํ•ฉ๋‹ˆ๋‹ค.
5257
/// </summary>
58+
/// <returns>๊ตฌ์„ฑ๋œ IServiceCollection์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.</returns>
5359
public static IServiceCollection AddOAuth2Authentication(this IServiceCollection services)
5460
{
5561
// OAuth2๋Š” ๋ณ„๋„ ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ์ฒ˜๋ฆฌํ•˜๋ฏ€๋กœ ๊ธฐ๋ณธ ์ธ์ฆ๋งŒ ์„ค์ •
@@ -64,7 +70,12 @@ public static IServiceCollection AddOAuth2Authentication(this IServiceCollection
6470

6571
/// <summary>
6672
/// ๊ฐœ๋ฐœ์šฉ CORS ์ •์ฑ…
73+
/// <summary>
74+
/// ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ ์‚ฌ์šฉํ•˜๋„๋ก ๋ชจ๋“  ์ถœ์ฒ˜, ๋ชจ๋“  HTTP ๋ฉ”์„œ๋“œ ๋ฐ ๋ชจ๋“  ํ—ค๋”๋ฅผ ํ—ˆ์šฉํ•˜๊ณ 
75+
/// "X-Access-Token", "X-Refresh-Token", "X-Expires-In", "X-UID" ์‘๋‹ต ํ—ค๋”๋ฅผ ๋…ธ์ถœํ•˜๋Š”
76+
/// "AllowAll" CORS ์ •์ฑ…์„ DI ์ปจํ…Œ์ด๋„ˆ์— ๋“ฑ๋กํ•ฉ๋‹ˆ๋‹ค.
6777
/// </summary>
78+
/// <returns>๊ตฌ์„ฑ๋œ IServiceCollection์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.</returns>
6879
public static IServiceCollection AddDevelopmentCors(this IServiceCollection services)
6980
{
7081
services.AddCors(options => {

โ€ŽProjectVG.Api/Controllers/AuthController.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,22 @@ public class AuthController : ControllerBase
99
{
1010
private readonly IAuthService _authService;
1111

12+
/// <summary>
13+
/// ์ปจํŠธ๋กค๋Ÿฌ์— ์ธ์ฆ ์„œ๋น„์Šค ์˜์กด์„ฑ์„ ์ฃผ์ž…ํ•˜์—ฌ ์ดˆ๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค.
14+
/// </summary>
1215
public AuthController(IAuthService authService)
1316
{
1417
_authService = authService;
1518
}
1619

20+
/// <summary>
21+
/// ์š”์ฒญ ํ—ค๋”์˜ ๋ฆฌํ”„๋ ˆ์‹œ ํ† ํฐ์œผ๋กœ ์•ก์„ธ์Šค/๋ฆฌํ”„๋ ˆ์‹œ ํ† ํฐ์„ ๊ฐฑ์‹ ํ•˜๊ณ  ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
22+
/// </summary>
23+
/// <remarks>
24+
/// ์š”์ฒญ ํ—ค๋” "X-Refresh-Token"์—์„œ ๋ฆฌํ”„๋ ˆ์‹œ ํ† ํฐ์„ ์ฝ์–ด IAuthService.RefreshTokenAsync๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.
25+
/// ์‘๋‹ต์€ { success = true, tokens = ..., user = ... } ํ˜•ํƒœ์˜ 200 OK ์ž…๋‹ˆ๋‹ค.
26+
/// </remarks>
27+
/// <returns>๊ฐฑ์‹ ๋œ ํ† ํฐ๊ณผ ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ํฌํ•จํ•œ 200 OK IActionResult.</returns>
1728
[HttpPost("refresh")]
1829
public async Task<IActionResult> RefreshToken()
1930
{
@@ -28,6 +39,13 @@ public async Task<IActionResult> RefreshToken()
2839
});
2940
}
3041

42+
/// <summary>
43+
/// ์š”์ฒญ ํ—ค๋”์˜ "X-Refresh-Token"์—์„œ ๋ฆฌํ”„๋ ˆ์‹œ ํ† ํฐ์„ ์ฝ์–ด ํ•ด๋‹น ํ† ํฐ์˜ ๋กœ๊ทธ์•„์›ƒ(๋ฌดํšจํ™”)์„ ์ˆ˜ํ–‰ํ•˜๊ณ  ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
44+
/// </summary>
45+
/// <returns>
46+
/// HTTP 200 ์‘๋‹ต์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ๋ณธ๋ฌธ์€ ์ต๋ช… ๊ฐ์ฒด๋กœ { success: bool, message: string } ํ˜•ํƒœ์ด๋ฉฐ,
47+
/// success๋Š” ๋กœ๊ทธ์•„์›ƒ ์„ฑ๊ณต ์—ฌ๋ถ€, message๋Š” "Logout successful" ๋˜๋Š” "Logout failed"์ž…๋‹ˆ๋‹ค.
48+
/// </returns>
3149
[HttpPost("logout")]
3250
public async Task<IActionResult> Logout()
3351
{
@@ -41,6 +59,12 @@ public async Task<IActionResult> Logout()
4159
});
4260
}
4361

62+
/// <summary>
63+
/// ๊ฒŒ์ŠคํŠธ ์‹๋ณ„์ž(guestId)๋ฅผ ์‚ฌ์šฉํ•ด ๊ฒŒ์ŠคํŠธ OAuth ๋กœ๊ทธ์ธ์œผ๋กœ ์‚ฌ์šฉ์ž์™€ ํ† ํฐ์„ ๋ฐœ๊ธ‰ํ•˜์—ฌ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
64+
/// </summary>
65+
/// <param name="guestId">ํด๋ผ์ด์–ธํŠธ์—์„œ ์ „๋‹ฌ๋œ ๊ฒŒ์ŠคํŠธ ๊ณ ์œ  ์‹๋ณ„์ž(๋นˆ ๊ฐ’์ด๋ฉด ์œ ํšจํ•˜์ง€ ์•Š์Œ).</param>
66+
/// <returns>์„ฑ๊ณต ์‹œ HTTP 200 ์‘๋‹ต์œผ๋กœ { success = true, tokens, user } ํ˜•ํƒœ์˜ ํŽ˜์ด๋กœ๋“œ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.</returns>
67+
/// <exception cref="ValidationException">guestId๊ฐ€ null ๋˜๋Š” ๋นˆ ๋ฌธ์ž์—ด์ธ ๊ฒฝ์šฐ ErrorCode.GUEST_ID_INVALID์™€ ํ•จ๊ป˜ ๋˜์ ธ์ง‘๋‹ˆ๋‹ค.</exception>
4468
[HttpPost("guest-login")]
4569
public async Task<IActionResult> GuestLogin([FromBody] string guestId)
4670
{
@@ -59,6 +83,10 @@ public async Task<IActionResult> GuestLogin([FromBody] string guestId)
5983
});
6084
}
6185

86+
/// <summary>
87+
/// HTTP ์š”์ฒญ ํ—ค๋” "X-Refresh-Token"์—์„œ ๋ฆฌํ”„๋ ˆ์‹œ ํ† ํฐ์„ ์ฝ์–ด ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
88+
/// </summary>
89+
/// <returns>ํ—ค๋”์— ์ง€์ •๋œ ์ฒซ ๋ฒˆ์งธ ํ† ํฐ ๊ฐ’ ๋˜๋Š” ํ—ค๋”๊ฐ€ ์—†์„ ๊ฒฝ์šฐ ๋นˆ ๋ฌธ์ž์—ด.</returns>
6290
private string GetRefreshTokenFromHeader()
6391
{
6492
return Request.Headers["X-Refresh-Token"].FirstOrDefault() ?? string.Empty;

โ€ŽProjectVG.Api/Controllers/ChatController.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,20 @@ public class ChatController : ControllerBase
1313
{
1414
private readonly IChatService _chatService;
1515

16+
/// <summary>
17+
/// IChatService๋ฅผ ์ฃผ์ž… ๋ฐ›์•„ ์ปจํŠธ๋กค๋Ÿฌ์˜ ์ฑ„ํŒ… ์„œ๋น„์Šค ์˜์กด์„ฑ์„ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
18+
/// </summary>
1619
public ChatController(IChatService chatService)
1720
{
1821
_chatService = chatService;
1922
}
2023

24+
/// <summary>
25+
/// ํ˜„์žฌ ์ธ์ฆ๋œ ์‚ฌ์šฉ์ž๋กœ๋ถ€ํ„ฐ ์ฑ„ํŒ… ์š”์ฒญ์„ ๋ฐ›์•„ ์ฑ„ํŒ… ์ฒ˜๋ฆฌ๋ฅผ ํ์— ๋“ฑ๋กํ•˜๊ณ  ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
26+
/// </summary>
27+
/// <param name="request">ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋ณด๋‚ธ ์ฑ„ํŒ… ์š”์ฒญ ๊ฐ์ฒด (Message, CharacterId ํฌํ•จ).</param>
28+
/// <returns>ํ์— ๋“ฑ๋ก๋œ ์ž‘์—…์˜ ๊ฒฐ๊ณผ๋ฅผ ํฌํ•จํ•œ HTTP 200 ์‘๋‹ต(IActionResult).</returns>
29+
/// <exception cref="ValidationException">์‚ฌ์šฉ์ž ์‹๋ณ„์ž(ClaimTypes.NameIdentifier)๊ฐ€ ์—†๊ฑฐ๋‚˜ GUID๋กœ ํŒŒ์‹ฑํ•  ์ˆ˜ ์—†์„ ๊ฒฝ์šฐ ๋ฐœ์ƒํ•˜๋ฉฐ, ErrorCode.AUTHENTICATION_FAILED๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค.</exception>
2130
[HttpPost]
2231
[JwtAuthentication]
2332
public async Task<IActionResult> ProcessChat([FromBody] ChatRequest request)

โ€ŽProjectVG.Api/Controllers/OAuthController.cs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@ public class OAuthController : ControllerBase
1212
private readonly IOAuth2Service _oauth2Service;
1313
private readonly IOAuth2ProviderFactory _providerFactory;
1414

15+
/// <summary>
16+
/// OAuth2 ๊ด€๋ จ ์„œ๋น„์Šค์™€ ๊ณต๊ธ‰์ž ํŒฉํ† ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ์ดˆ๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค.
17+
/// </summary>
18+
/// <remarks>
19+
/// ์ƒ์„ฑ์ž์—์„œ ์ „๋‹ฌ๋œ `IOptions&lt;OAuth2ProviderSettings&gt; oauth2Settings` ๊ฐ’์€ ํ˜„์žฌ ํ•„๋“œ๋กœ ์ €์žฅ๋˜๊ฑฐ๋‚˜ ์‚ฌ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
20+
/// </remarks>
1521
public OAuthController(
1622
IOAuth2Service oauth2Service,
1723
IOAuth2ProviderFactory providerFactory,
@@ -21,6 +27,10 @@ public OAuthController(
2127
_providerFactory = providerFactory;
2228
}
2329

30+
/// <summary>
31+
/// ์ง€์›๋˜๋Š” OAuth2 ์ œ๊ณต์ž ๋ชฉ๋ก์„ ์กฐํšŒํ•˜์—ฌ ์„ฑ๊ณต ์—ฌ๋ถ€์™€ ํ•จ๊ป˜ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
32+
/// </summary>
33+
/// <returns>HTTP 200 ์‘๋‹ต์œผ๋กœ { success = true, providers = [...] } ํ˜•ํƒœ์˜ JSON ๊ฒฐ๊ณผ๋ฅผ ํฌํ•จํ•œ IActionResult๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.</returns>
2434
[HttpGet("oauth2/providers")]
2535
public IActionResult GetSupportedProviders()
2636
{
@@ -32,6 +42,17 @@ public IActionResult GetSupportedProviders()
3242
});
3343
}
3444

45+
/// <summary>
46+
/// ์ง€์ •๋œ OAuth2 ๊ณต๊ธ‰์ž์— ๋Œ€ํ•œ PKCE ๊ฒ€์ฆ์„ ์ˆ˜ํ–‰ํ•˜๊ณ , ๊ณต๊ธ‰์ž๋ณ„ ์ธ์ฆ URL์„ ์ƒ์„ฑํ•˜์—ฌ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
47+
/// </summary>
48+
/// <param name="provider">์š”์ฒญํ•  OAuth2 ๊ณต๊ธ‰์ž ์ด๋ฆ„. ์ง€์›๋˜์ง€ ์•Š๋Š” ๊ณต๊ธ‰์ž๋ฉด ValidationException(ErrorCode.OAUTH2_PROVIDER_NOT_SUPPORTED)์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.</param>
49+
/// <param name="state">ํด๋ผ์ด์–ธํŠธ์—์„œ ์ „๋‹ฌํ•œ ์ƒํƒœ ํ† ํฐ(์˜ˆ: CSRF/์ƒํƒœ ๊ฒ€์ฆ์šฉ ์‹๋ณ„์ž).</param>
50+
/// <param name="code_challenge">PKCE ์ฝ”๋“œ ์ฑŒ๋ฆฐ์ง€(ํ•„์ˆ˜). ๋น„์–ด ์žˆ์œผ๋ฉด ValidationException(ErrorCode.OAUTH2_PKCE_INVALID)์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.</param>
51+
/// <param name="code_challenge_method">PKCE ๋ฉ”์„œ๋“œ(ํ˜„์žฌ "S256"๋งŒ ํ—ˆ์šฉ). ๋‹ค๋ฅธ ๊ฐ’์ด๋ฉด ValidationException(ErrorCode.OAUTH2_PKCE_INVALID)์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.</param>
52+
/// <param name="code_verifier">์˜ต์…˜์ธ PKCE ์ฝ”๋“œ ๋ฒ ๋ฆฌํŒŒ์ด์–ด(ํ›„์† ํ๋ฆ„์—์„œ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ์Œ).</param>
53+
/// <param name="client_redirect_uri">ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์›ํ•˜๋Š” ๋ฆฌ๋””๋ ‰์…˜ URI(์˜ต์…˜, ๊ณต๊ธ‰์ž๋ณ„ ์ฒ˜๋ฆฌ).</param>
54+
/// <returns>HTTP 200 ์‘๋‹ต์œผ๋กœ { success = true, provider, auth_url } ํ˜•ํƒœ์˜ JSON์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. auth_url์€ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋ฆฌ๋””๋ ‰์…˜ํ•ด์•ผ ํ•  ๊ณต๊ธ‰์ž ์ธ์ฆ URL์ž…๋‹ˆ๋‹ค.</returns>
55+
/// <exception cref="ValidationException">์ง€์›๋˜์ง€ ์•Š๋Š” ๊ณต๊ธ‰์ž ๋˜๋Š” PKCE ๊ฒ€์ฆ ์‹คํŒจ ์‹œ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ์šฉ๋˜๋Š” ErrorCode: OAUTH2_PROVIDER_NOT_SUPPORTED, OAUTH2_PKCE_INVALID.</exception>
3556
[HttpGet("oauth2/authorize/{provider}")]
3657
public async Task<IActionResult> OAuth2Authorize(
3758
string provider,
@@ -62,6 +83,19 @@ public async Task<IActionResult> OAuth2Authorize(
6283
});
6384
}
6485

86+
/// <summary>
87+
/// OAuth2 ์ฝœ๋ฐฑ ์—”๋“œํฌ์ธํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ณ , ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ์˜ ๋ฆฌ๋””๋ ‰์…˜ URL๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธํ•ฉ๋‹ˆ๋‹ค.
88+
/// </summary>
89+
/// <param name="provider">์„ ํƒ์  ๊ณต๊ธ‰์ž ์‹๋ณ„์ž(๊ฒฝ๋กœ ๋งค๊ฐœ๋ณ€์ˆ˜). ์ œ๊ณต๋˜์ง€ ์•Š์•„๋„ ๋ฉ๋‹ˆ๋‹ค.</param>
90+
/// <param name="code">OAuth2 ๊ณต๊ธ‰์ž๊ฐ€ ๋ฐ˜ํ™˜ํ•œ ์ธ์ฆ ์ฝ”๋“œ(์ฟผ๋ฆฌ). ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค.</param>
91+
/// <param name="state">์š”์ฒญ ์‹œ ์ „๋‹ฌ๋œ ์ƒํƒœ ๊ฐ’(์ฟผ๋ฆฌ). ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค.</param>
92+
/// <param name="error">๊ณต๊ธ‰์ž๊ฐ€ ๋ฐ˜ํ™˜ํ•œ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€(์ฟผ๋ฆฌ). ๊ธฐ๋ณธ๊ฐ’์€ null์ž…๋‹ˆ๋‹ค. ์กด์žฌํ•˜๋ฉด ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.</param>
93+
/// <returns>์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ์˜ RedirectUrl๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธํ•˜๋Š” <see cref="IActionResult"/>๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.</returns>
94+
/// <exception cref="ValidationException">
95+
/// error ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ๋น„์–ด์žˆ์ง€ ์•Š๊ฑฐ๋‚˜(code/state๊ฐ€ ๋ˆ„๋ฝ๋œ ๊ฒฝ์šฐ) ๊ฒ€์ฆ ์‹คํŒจ ์‹œ ๊ฐ๊ฐ ๋‹ค์Œ ์˜ค๋ฅ˜ ์ฝ”๋“œ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค:
96+
/// - OAUTH2_CALLBACK_FAILED: callback์—์„œ error๊ฐ€ ์ „๋‹ฌ๋œ ๊ฒฝ์šฐ
97+
/// - REQUIRED_PARAMETER_MISSING: code ๋˜๋Š” state๊ฐ€ ๋ˆ„๋ฝ๋œ ๊ฒฝ์šฐ
98+
/// </exception>
6599
[HttpGet("oauth2/callback")]
66100
[HttpGet("oauth2/callback/{provider}")]
67101
public async Task<IActionResult> OAuth2Callback(
@@ -85,6 +119,20 @@ public async Task<IActionResult> OAuth2Callback(
85119
return Redirect(result.RedirectUrl!);
86120
}
87121

122+
/// <summary>
123+
/// ์ฃผ์–ด์ง„ ์ƒํƒœ(state)์— ๋Œ€์‘ํ•˜๋Š” OAuth2 ํ† ํฐ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•˜์—ฌ ์‘๋‹ต ํ—ค๋”๋กœ ๋ฐ˜ํ™˜ํ•˜๊ณ  ํ•ด๋‹น ํ† ํฐ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ญ์ œํ•ฉ๋‹ˆ๋‹ค.
124+
/// </summary>
125+
/// <remarks>
126+
/// - ์š”์ฒญ ์ฟผ๋ฆฌ์˜ <c>state</c>๊ฐ€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค.
127+
/// - ์กฐํšŒํ•œ ํ† ํฐ ๋ฐ์ดํ„ฐ๋Š” ๋ฐ˜ํ™˜ ์งํ›„ ์‚ญ์ œ๋ฉ๋‹ˆ๋‹ค.
128+
/// - ๋ฐ˜ํ™˜ ์‹œ ๋‹ค์Œ ํ—ค๋”๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค: <c>X-Access-Token</c>, <c>X-Refresh-Token</c>, <c>X-Expires-In</c>, <c>X-UID</c>.
129+
/// </remarks>
130+
/// <param name="state">ํ† ํฐ ์กฐํšŒ๋ฅผ ์‹๋ณ„ํ•˜๋Š” ์ƒํƒœ ์‹๋ณ„์ž(์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ). ๋นˆ๊ฐ’์ด๋ฉด ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.</param>
131+
/// <returns>์š”์ฒญ์ด ์„ฑ๊ณตํ•˜๋ฉด HTTP 200๊ณผ { success = true }๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.</returns>
132+
/// <exception cref="ValidationException">๋‹ค์Œ ์ƒํ™ฉ์—์„œ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค:
133+
/// - <see cref="ErrorCode.REQUIRED_PARAMETER_MISSING"/>: state๊ฐ€ ๋น„์–ด์žˆ์„ ๋•Œ.
134+
/// - <see cref="ErrorCode.OAUTH2_REQUEST_NOT_FOUND"/>: ํ•ด๋‹น state์— ๋Œ€ํ•œ ํ† ํฐ ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์„ ๋•Œ.
135+
/// </exception>
88136
[HttpGet("oauth2/token")]
89137
public async Task<IActionResult> GetOAuth2Token([FromQuery] string state)
90138
{

โ€ŽProjectVG.Api/Filters/JwtAuthenticationFilter.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,18 @@ namespace ProjectVG.Api.Filters
77
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
88
public class JwtAuthenticationAttribute : Attribute, IAsyncAuthorizationFilter
99
{
10+
/// <summary>
11+
/// ์š”์ฒญ์—์„œ Bearer JWT๋ฅผ ์ถ”์ถœยท๊ฒ€์ฆํ•˜๊ณ  ์„ฑ๊ณต ์‹œ HttpContext.User์— ClaimsPrincipal์„ ์„ค์ •ํ•˜์—ฌ ์ธ์ฆ์„ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค.
12+
/// </summary>
13+
/// <param name="context">ํ˜„์žฌ ์š”์ฒญ์˜ ์ปจํ…์ŠคํŠธ(์š”์ฒญ ํ—ค๋”์—์„œ ํ† ํฐ์„ ์ฝ๊ณ , HttpContext.User๋ฅผ ์„ค์ •ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ).</param>
14+
/// <returns>๋น„๋™๊ธฐ ์ž‘์—…์„ ๋‚˜ํƒ€๋‚ด๋Š” Task.</returns>
15+
/// <exception cref="AuthenticationException">๋‹ค์Œ ์กฐ๊ฑด ์ค‘ ํ•˜๋‚˜์ผ ๋•Œ ๋ฐœ์ƒ:
16+
/// <list type="bullet">
17+
/// <item><description>ErrorCode.TOKEN_MISSING: ํ† ํฐ์ด ํ—ค๋”์— ์—†๊ฑฐ๋‚˜ ๋น„์–ด ์žˆ์„ ๋•Œ.</description></item>
18+
/// <item><description>ErrorCode.TOKEN_INVALID: ํ† ํฐ์ด ์œ ํšจํ•˜์ง€ ์•Š์„ ๋•Œ.</description></item>
19+
/// <item><description>ErrorCode.AUTHENTICATION_FAILED: ํ† ํฐ์—์„œ ์‚ฌ์šฉ์ž ID๋ฅผ ์–ป์„ ์ˆ˜ ์—†์„ ๋•Œ.</description></item>
20+
/// </list>
21+
/// </exception>
1022
public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
1123
{
1224
var logger = context.HttpContext.RequestServices.GetRequiredService<ILogger<JwtAuthenticationAttribute>>();
@@ -36,6 +48,11 @@ public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
3648
logger.LogInformation("JWT ์ธ์ฆ ์„ฑ๊ณต - ์‚ฌ์šฉ์ž: {UserId}", userId.Value);
3749
}
3850

51+
/// <summary>
52+
/// ์š”์ฒญ ํ—ค๋”๋“ค์—์„œ Bearer ํ† ํฐ์„ ์ฐพ์•„ ํ† ํฐ ๋ฌธ์ž์—ด์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
53+
/// </summary>
54+
/// <param name="request">ํ† ํฐ์„ ์ถ”์ถœํ•  HTTP ์š”์ฒญ.</param>
55+
/// <returns>ํ—ค๋”์—์„œ ์ฐพ์€ ํ† ํฐ ๋ฌธ์ž์—ด(์ ‘๋‘์‚ฌ "Bearer " ์ œ๊ฑฐ) ๋˜๋Š” ์ฐพ์ง€ ๋ชปํ•˜๋ฉด null.</returns>
3956
private string? ExtractToken(HttpRequest request)
4057
{
4158
var possibleHeaders = new[]

โ€ŽProjectVG.Api/Middleware/GlobalExceptionHandler.cs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,14 @@ private async Task HandleExceptionAsync(HttpContext context, Exception exception
4646
await context.Response.WriteAsync(jsonResponse);
4747
}
4848

49+
/// <summary>
50+
/// ์ „๋‹ฌ๋œ ์˜ˆ์™ธ๋ฅผ ์ ์ ˆํ•œ ์ „์šฉ ํ•ธ๋“ค๋Ÿฌ๋กœ ๋งคํ•‘ํ•˜์—ฌ ํ‘œ์ค€ํ™”๋œ ErrorResponse๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
51+
/// </summary>
52+
/// <remarks>
53+
/// ValidationException, NotFoundException, AuthenticationException, ProjectVGException, ExternalServiceException,
54+
/// DbUpdateException ๋“ฑ ์•Œ๋ ค์ง„ ์˜ˆ์™ธ๋Š” ๊ฐ ์ „์šฉ ์ฒ˜๋ฆฌ ๋ฉ”์„œ๋“œ๋กœ ์œ„์ž„๋˜๊ณ , ํ•ด๋‹นํ•˜์ง€ ์•Š๋Š” ์˜ˆ์™ธ๋Š” HandleGenericException์—์„œ ์ฒ˜๋ฆฌ๋ฉ๋‹ˆ๋‹ค.
55+
/// ๋ฐ˜ํ™˜๋˜๋Š” ErrorResponse๋Š” ํด๋ผ์ด์–ธํŠธ์— ์ง๋ ฌํ™”๋˜์–ด HTTP ์‘๋‹ต ํŽ˜์ด๋กœ๋“œ๋กœ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
56+
/// </remarks>
4957
private ErrorResponse CreateErrorResponse(Exception exception, HttpContext context)
5058
{
5159
if (exception is ValidationException validationEx) {
@@ -115,6 +123,15 @@ private ErrorResponse HandleValidationException(ValidationException exception, H
115123
};
116124
}
117125

126+
/// <summary>
127+
/// NotFoundException์„ ErrorResponse๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
128+
/// </summary>
129+
/// <param name="exception">๋ฐœ์ƒํ•œ NotFoundException(๋‚ด๋ถ€์— ErrorCode, Message, StatusCode ํฌํ•จ).</param>
130+
/// <param name="context">์‘๋‹ต์— ํฌํ•จํ•  TraceIdentifier๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•œ HttpContext.</param>
131+
/// <returns>
132+
/// ์š”์ฒญ๋œ ๋ฆฌ์†Œ์Šค๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Œ์„ ๋‚˜ํƒ€๋‚ด๋Š” ErrorResponse:
133+
/// ErrorCode, Message, StatusCode, UTC ํƒ€์ž„์Šคํƒฌํ”„, TraceId๋ฅผ ์„ค์ •ํ•˜์—ฌ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
134+
/// </returns>
118135
private ErrorResponse HandleNotFoundException(NotFoundException exception, HttpContext context)
119136
{
120137
_logger.LogWarning(exception, "๋ฆฌ์†Œ์Šค๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Œ: {ErrorCode} - {Message}", exception.ErrorCode.ToString(), exception.Message);
@@ -128,6 +145,12 @@ private ErrorResponse HandleNotFoundException(NotFoundException exception, HttpC
128145
};
129146
}
130147

148+
/// <summary>
149+
/// ์ธ์ฆ ๊ด€๋ จ ์˜ˆ์™ธ(AuthenticationException)๋ฅผ ํ‘œ์ค€ํ™”๋œ ErrorResponse๋กœ ๋ณ€ํ™˜ํ•˜๊ณ  ๊ฒฝ๊ณ ๋ฅผ ๊ธฐ๋กํ•ฉ๋‹ˆ๋‹ค.
150+
/// </summary>
151+
/// <param name="exception">์ฒ˜๋ฆฌํ•  AuthenticationException ์ธ์Šคํ„ด์Šค.</param>
152+
/// <param name="context">ํ˜„์žฌ HTTP ์š”์ฒญ์˜ HttpContext; ์‘๋‹ต์— ํฌํ•จํ•  TraceIdentifier๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.</param>
153+
/// <returns>์˜ˆ์™ธ ์ •๋ณด๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์ƒ์„ฑ๋œ ErrorResponse(์—๋Ÿฌ ์ฝ”๋“œ, ๋ฉ”์‹œ์ง€, ์ƒํƒœ ์ฝ”๋“œ, ํƒ€์ž„์Šคํƒฌํ”„, TraceId ํฌํ•จ).</returns>
131154
private ErrorResponse HandleAuthenticationException(AuthenticationException exception, HttpContext context)
132155
{
133156
_logger.LogWarning(exception, "์ธ์ฆ ์‹คํŒจ: {ErrorCode} - {Message}", exception.ErrorCode.ToString(), exception.Message);
@@ -141,6 +164,12 @@ private ErrorResponse HandleAuthenticationException(AuthenticationException exce
141164
};
142165
}
143166

167+
/// <summary>
168+
/// ProjectVG ์ „์šฉ ์˜ˆ์™ธ๋ฅผ ํ‘œ์ค€ ErrorResponse๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
169+
/// </summary>
170+
/// <param name="exception">ErrorCode, Message, StatusCode ๋“ฑ์„ ํฌํ•จํ•œ ProjectVG ์˜ˆ์™ธ; ์‘๋‹ต์˜ ์ฃผ์š” ํ•„๋“œ ๊ฐ’์œผ๋กœ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.</param>
171+
/// <param name="context">์‘๋‹ต์— ํฌํ•จํ•  TraceId๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋˜๋Š” HttpContext.</param>
172+
/// <returns>์˜ˆ์™ธ ์ •๋ณด๋ฅผ ๋งคํ•‘ํ•œ ErrorResponse(UTC ํƒ€์ž„์Šคํƒฌํ”„์™€ TraceId ํฌํ•จ).</returns>
144173
private ErrorResponse HandleProjectVGException(ProjectVGException exception, HttpContext context)
145174
{
146175
_logger.LogWarning(exception, "ProjectVG ์˜ˆ์™ธ ๋ฐœ์ƒ: {ErrorCode} - {Message}", exception.ErrorCode.ToString(), exception.Message);

0 commit comments

Comments
ย (0)