๐Ÿ“Œ Spring ํ”Œ๋Ÿฌ์Šค ์ฃผ์ฐจ ๊ฐœ์ธ ๊ณผ์ œ ํŠธ๋Ÿฌ๋ธ” ์ŠˆํŒ…

euphonyยท2025๋…„ 3์›” 21์ผ
0

๋‚ด์ผ๋ฐฐ์›€์บ ํ”„

๋ชฉ๋ก ๋ณด๊ธฐ
61/66

ํ•™์Šตํ•œ ๋‚ด์šฉ ์ •๋ฆฌ

๊ณผ์ œ๋ฅผ ํ•˜๋ฉฐ ํ‹ˆํ‹ˆ์ด ํ•œ ๊ณต๋ถ€ ๊ธฐ๋ก.โœ๐Ÿป ์•„์ง๋„ ์ •๋ฆฌํ•  ๊ฒƒ๋“ค & ์“ฐ๊ณ  ์žˆ๋Š” ๊ฒƒ๋“ค์ด ์‚ฐ๋”๋ฏธ๋ผ์„œ ์˜ฌ๋ฆฌ์ง€ ๋ชปํ•œ ๊ธฐ๋ก์ด ๋งŽ๋‹ค. ๋นจ๋ฆฌ ์จ์„œ ์˜ฌ๋ ค์•ผ๊ฒ ๋‹ค!

Spring Security ๋„์ž… ํ›„ NullPointException

์–ด์ œ Spring Security ๋„์ž…์„ ๋งˆ๋ฌด๋ฆฌ ํ•˜๊ณ , ๋‹ค์Œ ๋‹จ๊ณ„๋ฅผ ์ง„ํ–‰ํ•˜๋‹ค๊ฐ€ ์ผ์ •์„ ์ƒ์„ฑํ•˜๋Š” ๋ถ€๋ถ„์—์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด NPE๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค.

Postman์—์„œ๋Š” 403 Forbidden ์—๋Ÿฌ๊ฐ€ ๋‚œ ์ƒํ™ฉ์ด๋‹ค.

ํšŒ์›๊ฐ€์ž…๊ณผ ๋กœ๊ทธ์ธ์€ ์ •์ƒ์ ์œผ๋กœ ๋๊ณ , DB์—๋„ ๋ชจ๋“  ์ •๋ณด๊ฐ€ ๋‹ค ๋น ์ง์—†์ด ๋“ค์–ด์žˆ๋‹ค.

์™œ userRole์ด null์ธ๊ฐ€...๐Ÿค” DB์—๋„ ๋‹ค ๋“ค์–ด์žˆ๋Š”๋ฐ ์™œ null์ด์ง€...?

์ด ์ƒํ™ฉ์„ ๋ฏฟ์„ ์ˆ˜๊ฐ€ ์—†์–ด ์ƒ์„ฑ์ž์—์„œ userRole์ด null์ผ ๋•Œ ์—๋Ÿฌ๋ฅผ ๋˜์ง€๋„๋ก ํ•ด ๋‹ค์‹œ ํ•œ ๋ฒˆ ํ™•์ธํ•ด๋ดค๋‹ค.

null์ด ๋งž๋‹ค. ๊ทธ๋ ‡๋‹ค๋ฉด ์™œ์ผ๊นŒ?

๊ฒ€์ƒ‰์˜ ๋Šช์— ๋น ์ ธ์žˆ๋‹ค๊ฐ€ ์—ฌ๋Ÿฌ ์ƒํ™ฉ์„ ๊ฐ€์ •ํ•˜๊ณ  ํ™•์ธํ•ด๋ณด์•˜๋‹ค.

  • JwtUtil๊ณผ JwtAuthenticationFilter์—์„œuserRole์„ ๋‹ค๋ฅธ ๋‹จ์–ด๋กœ ์ž…๋ ฅํ•œ ๊ฒฝ์šฐ โ†’ ๋‘˜ ๋‹ค userRole๋กœ ๊ฐ™์Œ.
  • DB์— ์ €์žฅ๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ โ†’ ์•„์ฃผ ์ž˜ ์ €์žฅ๋˜์–ด์žˆ์Œ.
  • JWT ์ƒ์„ฑ ์‹œ userRole์ด ํฌํ•จ๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ โ†’ ์ด ๋ถ€๋ถ„์€ ์›๋ž˜ ์žˆ๋˜ ์ฝ”๋“œ๋ผ ๊ทธ๋Ÿด ๋ฆฌ ์—†์Œ.
  • AuthUser๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ถ€๋ถ„์—์„œ null์ด ๋“ค์–ด๊ฐ€๊ณ  ์žˆ๋Š” ๊ฒƒ ๊ฐ™์€๋ฐ, AuthUser๋ฅผ ๋งŒ๋“ค๊ณ  ์žˆ๋Š” ๋ถ€๋ถ„์„ ์ฐพ์•„๋ณด์ž โ†’ ์ด ํ๋ฆ„์ด ๋งž์•˜์Œ!

JwtAuthenticationFilter์—์„œ setAuthentication()์„ ๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค. ์—ฌ๊ธฐ์„œ ํ•ด๋‹น ๋ฉ”์„œ๋“œ๋Š” JWT ํ† ํฐ์„ ๊ฒ€์ฆํ•œ ํ›„, Spring Security์˜ SecurityContext์— ์ธ์ฆ๋œ ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ์ €์žฅํ•˜๋Š” ์—ญํ• ์„ ํ•œ๋‹ค. ์—ฌ๊ธฐ์„œ JwtAuthenticationToken ๋ถ€๋ถ„์„ ๋ณด๋ฉด Spring Security์—์„œ ์‚ฌ์šฉํ•  Authentication ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

JwtAuthenticationToken ํด๋ž˜์Šค๋กœ ๊ฐ€์„œ ๋‹ค์‹œ ํ•œ ๋ฒˆ ์‚ดํŽด๋ณด๋‹ˆ ์‚ฌ์šฉ์ž์˜ ๊ถŒํ•œ(userRole)์„ ์„ค์ •ํ•˜๊ณ , ์ธ์ฆ๋œ ์‚ฌ์šฉ์ž๋กœ setํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋งจ ์•„๋ž˜ getPrincipal() ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ํ˜„์žฌ ๋กœ๊ทธ์ธํ•œ ์‚ฌ์šฉ์ž์˜ ์ •๋ณด๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ์—ฌ๊ธฐ์„œ ์ด getPrincipal() ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์ง€ ์•Š๋‹ค๋Š” ๊ฒƒ์„ ๊นจ๋‹ฌ์•˜๋‹ค.

๋”ฐ๋ผ์„œ ๋‚˜๋Š” ์ด ๋ถ€๋ถ„์„ ์ด์šฉํ•ด์•ผ ํ•œ๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ค์–ด TodoController์˜ saveTodo() ๋ฉ”์„œ๋“œ์—์„œ @Auth ์–ด๋…ธํ…Œ์ด์…˜์„ ์ฃผ์„ ์ฒ˜๋ฆฌํ•œ ํ›„, ์ง์ ‘ getPrincipal() ๋ฉ”์„œ๋“œ๋ฅผ ๋ถˆ๋Ÿฌ authUser์— ๋„ฃ๊ณ  ํ…Œ์ŠคํŠธ ํ•ด๋ดค๋‹ค.

๋“œ๋””์–ด ์ œ๋Œ€๋กœ ์ผ์ •์ด ์ƒ์„ฑ๋˜์—ˆ๋‹ค! ํ•˜์ง€๋งŒ @Auth๋ฅผ ์ด์šฉํ•ด ๋ฐ”๊ฟ”์•ผ ํ–ˆ๋Š”๋ฐ, ์ด ๋ถ€๋ถ„์—์„œ ๋‚ด๊ฐ€ ์–ด์ œ ์‹ค์ˆ˜๋ฅผ ํ–ˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ฒŒ๋˜์—ˆ๋‹ค.

๋ฐ”๋กœ ํŒŒ์ผ ์ •๋ฆฌ๋ฅผ ํ•˜๋‹ค๊ฐ€ ์ƒ๊ฐ์—†์ด AuthUserArgumentResolver์™€ WebConfig๋ฅผ ์‚ญ์ œํ•ด๋ฒ„๋ฆฐ ๊ฒƒ์ด๋‹ค.... ์ด ๋ถ€๋ถ„์€ ์‚ญ์ œํ•˜์ง€ ๋ง๊ณ  Spring Security๋กœ ๋ณ€๊ฒฝํ–ˆ์–ด์•ผ ํ–ˆ๋Š”๋ฐ, ํ•„์š”์—†๋‹ค๊ณ  ์ƒ๊ฐํ•ด์„œ ์ง€์› ๋‹ค. ์ฐจ๋ผ๋ฆฌ ์ง€์šฐ์ง€ ์•Š์•˜๋”๋ผ๋ฉด ๋” ๋นจ๋ฆฌ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์—ˆ์„ ํ…๋ฐ ๋ง์ด๋‹ค. ์ •ํ™•ํ•œ ์ดํ•ด ์—†์ด ์ ์šฉํ•˜๋ ค๊ณ ๋งŒ ํ•ด์„œ ์ด๋Ÿฐ ์ผ์ด ๋ฒŒ์–ด์ง„ ๊ฒƒ ๊ฐ™๋‹ค.๐Ÿ˜“

๋”ฐ๋ผ์„œ ๋‹ค์‹œ ํ•ด๋‹น ํŒŒ์ผ์„ ๋งŒ๋“  ํ›„, AuthUserArgumentResolver์˜ resolveArgument()๋ฉ”์„œ๋“œ๋ฅผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ˆ˜์ •ํ–ˆ๋‹ค. ์ด์ „์—๋Š” ๊ฐ’์„ request์—์„œ ํ•˜๋‚˜์”ฉ ๊ฐ€์ ธ์™€ ์ƒˆ๋กœ์šด AuthUser ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด ๋ฐ˜ํ™˜ํ–ˆ๋‹ค.

์ˆ˜์ • ํ›„, ํ˜„์žฌ ์ธ์ฆ๋œ ์‚ฌ์šฉ์ž์˜ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์™€์„œ(SecurityContextHolder.getContext().getAuthentication()) Principal์„ ๊บผ๋‚ด(getPrincipal()) AuthUser๋กœ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ์ด๋ ‡๊ฒŒ ๋ฐ˜ํ™˜๋œ AuthUser๋Š” TodoController์˜ authUser ํŒŒ๋ผ๋ฏธํ„ฐ์— ์ž๋™์œผ๋กœ ๋“ค์–ด๊ฐ„๋‹ค.

๋”ฐ๋ผ์„œ ๊ธฐ์กด๊ณผ ๊ฐ™์ด ์ด๋ ‡๊ฒŒ ์ ์–ด์ค˜๋„ ์ด์ œ ์ •์ƒ์ ์œผ๋กœ ๋“ค์–ด๊ฐ„๋‹ค.

Postman์—์„œ๋„ ์ž˜ ํ…Œ์ŠคํŠธ ๋œ๋‹ค.

์ž, ์ด๋ ‡๊ฒŒ ๊ฒจ์šฐ๊ฒจ์šฐ ์—๋Ÿฌ๋ฅผ ํ•ด๊ฒฐํ–ˆ์ง€๋งŒ ์ด ๋ฐฉ๋ฒ•์„ ์•„๋ž˜ ์–ด๋…ธํ…Œ์ด์…˜ ํ•˜๋‚˜๋กœ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

@AuthenticationPrincipal'

์ด๋ ‡๊ฒŒ ๋ฐ”๊พธ๋ฉด ๋ฐ”๋กœ ์ ์šฉ ๊ฐ€๋Šฅํ•˜๋‹ค.

...๋‚˜ ์˜ค๋Š˜ ๋ญํ•œ๊ฑฐ์ง€...?๐Ÿ™„ ํŒ€์› ๋ถ„์ด ๋งˆ์ง€๋ง‰ ์Šคํฌ๋Ÿผ๋•Œ ์•Œ๋ ค์ฃผ์…”์„œ ์•Œ์•˜๋‹ค. ๊ฐ•์˜๋ฅผ ๋” ์ž์„ธํžˆ ๋ด์•ผํ•œ๋‹ค๋Š” ๊ตํ›ˆ์„ ์–ป์—ˆ๋‹ค.

๋นŒ๋“œ ๊ณผ์ •์—์„œ ๋ฐœ์ƒํ•œ ์˜ค๋ฅ˜

  • Error creating bean with name 'jwtAuthenticationFilter' defined in file ... ์˜ค๋ฅ˜
    • JwtAuthenticationFilter ํด๋ž˜์Šค๊ฐ€ JwtUtil์„ ์ฃผ์ž…๋ฐ›์œผ๋ ค๊ณ  ํ–ˆ๋Š”๋ฐ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— JwtUtil ๋นˆ์ด ๋“ฑ๋ก๋˜์–ด ์žˆ์ง€ ์•Š์•„ ๋ฐœ์ƒํ•œ ์˜ค๋ฅ˜์ด๋‹ค.
    • JwtUtil์„ Mock์œผ๋กœ ์ฃผ์ž…ํ•ด ํ•ด๊ฒฐํ•˜์˜€๋‹ค.
  • Spring Security ์ธ์ฆ์ด ๊ฑธ๋ฆฌ๋Š” ํ…Œ์ŠคํŠธ๊ฐ€ ์žˆ์–ด ์ธ์ฆ ๊ฐ์ฒด๊ฐ€ ํ•„์š”ํ•˜๋‹ค๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ๋‹ค.
    • @WithMockUser์„ ์ถ”๊ฐ€ํ•ด ํ…Œ์ŠคํŠธ์šฉ์œผ๋กœ ๊ฐ€์งœ ์ธ์ฆ ๊ฐ์ฒด(SecurityContext)์— ๋„ฃ์–ด์ฃผ๋Š” ์—ญํ• ์„ ํ•˜๋„๋ก ํ–ˆ๋‹ค.

๋ฐฐํฌ ๊ณผ์ •์—์„œ ๋ฐœ์ƒํ•œ ์˜ค๋ฅ˜

  • MySQL ์—ฐ๊ฒฐ ์‹คํŒจ ์˜ค๋ฅ˜ ๋ฐœ์ƒ
    • DB URL์—์„œ localhost๋กœ ๋˜์–ด ์žˆ์œผ๋ฉด EC2๊ฐ€ ์ž๊ธฐ ์ž์‹ ์„ ์ฐพ๋‹ค๊ฐ€ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค๊ณ  ํ•œ๋‹ค.
    • ์ด๋•Œ๋Š” RDS๋ฅผ ๊ตฌ์ถ•ํ•˜์ง€ ์•Š์€ ์ƒํƒœ์—ฌ์„œ ์ผ๋‹จ DB ์—ฐ๊ฒฐ ์—†์ด ์„œ๋ฒ„๋งŒ ์‹คํ–‰ํ•˜๋Š” ๋ฐฉํ–ฅ์œผ๋กœ ์‹œ๋„ํ–ˆ๋‹ค.
    • ๋”ฐ๋ผ์„œ ์•„๋ž˜์™€ ๊ฐ™์ด application.properties์—์„œ DB ์„ค์ •์„ ์ฃผ์„ ์ฒ˜๋ฆฌํ•œํ›„ ๋‹ค์‹œ ๋นŒ๋“œํ–ˆ๋‹ค.
  • 8080 ํฌํŠธ๋ฅผ ์ด๋ฏธ ๋‹ค๋ฅธ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์žก๊ณ  ์žˆ๋Š” ๋ฌธ์ œ ๋ฐœ์ƒ
    • ์ƒˆ๋กœ ๋นŒ๋“œํ•˜๊ณ  ๋ฐฐํฌ ํ›„ ๋‹ค์‹œ ์‹คํ–‰ํ•˜๋ ค๊ณ  ํ•˜์ž ์œ„์™€ ๊ฐ™์€๋ฉ”์„ธ์ง€๊ฐ€ ๋‚˜์™”๋‹ค. ๊ธฐ์กด์— ์‹คํ–‰ํ•œ java -jar ํ”„๋กœ์„ธ์Šค๊ฐ€ ์•„์ง ์‚ด์•„์žˆ๊ฑฐ๋‚˜ ๋‘ ๋ฒˆ ์‹คํ–‰ํ•ด ํฌํŠธ ์ถฉ๋Œ์ด ๋‚œ ๊ฒƒ์ด๋‹ค.
    • ps -ef | grep java ๋ช…๋ น์–ด๋ฅผ ์ด์šฉํ•ด PID๋ฅผ ํ™•์ธ ํ›„, kill -9 [PID] ๋ช…๋ น์–ด๋กœ ๊ธฐ์กด ํ”„๋กœ์„ธ์Šค๋ฅผ ์ข…๋ฃŒํ•œ ํ›„, ๋‹ค์‹œ ์„œ๋ฒ„๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.
  • ์ ‘์†์ด ์•ˆ๋œ๋‹ค๋ฉด ๋ณด์•ˆ ๊ทœ์น™์—์„œ 8080 ํฌํŠธ๊ฐ€ ์—ด๋ ค ์žˆ๋Š”์ง€ ํ™•์ธํ•œ๋‹ค. ๋งŒ์•ฝ ์—ด๋ ค์žˆ์ง€ ์•Š๋‹ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด Inbound rules์— 8080 ํฌํŠธ๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.
  • nohup java -jar expert-0.0.1-SNAPSHOT.jar & ๋ช…๋ น์–ด ์˜ค๋ฅ˜ : nohup: failed to run command 'java': No such file or directory ๋ผ๋Š” ์˜ค๋ฅ˜ ๋ฉ”์„ธ์ง€๊ฐ€ ๋‚˜ํƒ€๋‚ฌ๋‹ค. EC2 ์ธ์Šคํ„ด์Šค์— Java๊ฐ€ ์„ค์น˜๋˜์–ด ์žˆ์ง€ ์•Š์•„์„œ ๋ฐœ์ƒํ•œ ์˜ค๋ฅ˜์ด๋‹ค. ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ช…๋ น์–ด๋ฅผ ์ž…๋ ฅํ•ด Java๋ฅผ ์„ค์น˜ ํ›„ ๋‹ค์‹œ ์‹œ๋„ํ•œ๋‹ค.
   sudo apt update
   sudo apt install openjdk-17-jdk -y

DB ์—ฐ๊ฒฐ ์‹คํŒจ ๋ฌธ์ œ

  • ํ…Œ์ŠคํŠธ ์‹คํ–‰ ์ค‘ DB(MySQL) ์—ฐ๊ฒฐ ์‹คํŒจ, ์ฆ‰ JDBC โ†’ MySQL๋กœ ์—ฐ๊ฒฐ ์‹œ๋„ํ•˜๋‹ค๊ฐ€ ์‹คํŒจ
  • java.net.ConnectException โ†’ ์•„์˜ˆ DB๋กœ ๋„คํŠธ์›Œํฌ ์—ฐ๊ฒฐ ์ž์ฒด๊ฐ€ ์•ˆ ๋œ ์ƒํƒœ

โ‡’ RDS ์—ฐ๊ฒฐ๋งŒ ๋‚จ์•„ ์žˆ์–ด์„œ ํ…Œ์ŠคํŠธ ๋Œ๋ฆฌ๋‹ˆ๊นŒ RDS๋กœ ๋ถ™์œผ๋ ค๋‹ค๊ฐ€ ์‹คํŒจํ•œ ์ƒํ™ฉ

๋”ฐ๋ผ์„œ ๋‹ค์Œ ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ• ์ค‘ ํ•˜๋‚˜๋ฅผ ์„ ํƒํ–ˆ๋‹ค.

  1. RDS ์—ฐ๊ฒฐํ•ด ํ…Œ์ŠคํŠธ
  2. H2๋กœ ํ…Œ์ŠคํŠธ โ† ๋กœ์ปฌ์—์„œ๋Š” ์ด๊ฑธ ํ•˜์ž!
  • application-local.properties๋ฅผ ๋”ฐ๋กœ ๋งŒ๋“ค์–ด ํ•ด๊ฒฐํ–ˆ๋‹ค.
  • ๋กœ์ปฌ์—์„œ ๊ธฐ๋ณธ์ ์œผ๋กœ application-local.properties ๋กœ ์‹คํ–‰ โ†’ application.properties์— spring.profiles.active=local ์ถ”๊ฐ€
  • git bash์— ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์—ฐ๊ฒฐํ•œ๋‹ค.

  • application-local.properties ํŒŒ์ผ์„ ์ฝ์–ด๋ผ! ๋ผ๋Š” ๋œป.
  • ์ด๋ ‡๊ฒŒ local์„ ๋ช…์‹œํ•ด์•ผ ๋กœ์ปฌ DB ์—ฐ๊ฒฐ, ๋กœ์ปฌ์šฉ S3 ํ‚ค๋กœ ํ…Œ์ŠคํŠธ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค.

0๊ฐœ์˜ ๋Œ“๊ธ€

๊ด€๋ จ ์ฑ„์šฉ ์ •๋ณด