โ๏ธDate : 2022.11.08 ~ 2022.12.07
What did you do?
๐ฉ๐ป๐พ ์์ฒด ๋ก๊ทธ์ธ๊ณผ ์์ ๋ก๊ทธ์ธ ๊ตฌํ
- JWT ํ ํฐ์ ์ด์ฉํ ์์ฒด ๋ก๊ทธ์ธ๊ณผ ์์ ๋ก๊ทธ์ธ ๊ตฌํ
- REST API๋ฅผ ์ด์ฉํ์ฌ ๊ตฌํ
- ํ๋ก์ ํธ ์ดํ ๋๋ฐธ๋กญ : ํํฐ๋ฅผ ์ด์ฉํ์ฌ ์์ฒด ๋ก๊ทธ์ธ๊ณผ ์์ ๋ก๊ทธ์ธ ๊ตฌํ, ์์ ๋ก๊ทธ์ธ ๋ฆฌ๋ค์ด๋ ํธ ์ header๋ก ํ ํฐ ์ ๋ฌ
: ์ ๋ฒ ํ๋ฆฌ ํ๋ก์ ํธ ๋์ ์์ ๋ก๊ทธ์ธ๊ณผ ์์ฒด ๋ก๊ทธ์ธ์ ๋์์ ๊ตฌํํด๋ด์ง ๋ชปํ๋ค. ๋๋ฌธ์ ์ด๋ฒ์๋ ๋ฌด์กฐ๊ฑด ํด๋ด๊ณ ์ถ๋ค๋ ์๊ฐ์ด ๋ค์๋ค. ๊ทธ๋์ ๋ก๊ทธ์ธ ํํธ๋ฅผ ๋ค์ ๋ง๋ค๊ฒ ๋์์ ๋, ์์ฌ์ ์ข ๋ด๋ณด๋ ค๊ณ ํ๋ค. ์ฒ์์ ํํฐ๋ก ์ฌ์ฉํด๋ณด๋ ค๊ณ ํ์ผ๋, ์์ ๋ก๊ทธ์ธ์ ์ญํ ๊ตฌ๋ถ์์ ๋ฆฌ๋ค์ด๋ ํธ ์ํฌ ์ ์๋ ๋ฐฉ๋ฒ์ด ์ด๋ ค์ ๋ค. ๊ทธ๋์ ๋ฐ์ ๋ฐ ์ ๋ ๊ตฌํํ์ ๋์ ์ผ์ ๋ด์ ํด๋ด์ง ๋ชปํ ๊ฒ ๊ฐ์ REST API๋ก ๊ตฌํํ๋ ๊ฒ์ผ๋ก ์์ ํ์๋ค. REST API๋ก ๊ตฌํํ๋ฉด ๋ด๊ฐ ์กฐ๊ธ ๋ ์ปค์คํ ํ๊ธฐ ์ฝ์ง ์์๊น ํ๋ ์๊ฐ ๋๋ฌธ์ด์๋ค. ์ค์ ๋ก๋ ์กฐ๊ธ ๋ ์ปค์คํ ํ๊ธฐ ์ฌ์ ๋ ๊ฒ ๊ฐ๋ค. ์๋น์ค ๊ณ์ธต์์ ํ ํฐ์ ์ง์ ๋ฐ๊ธ ๋ฐ๊ณ ์ปจํธ๋กค๋ฌ์์ ํค๋์ ๋๊ธธ ์ ์๋๋ก ์ค๊ณํ์๋ค. ๋ํ ์์ ๋ก๊ทธ์ธ์ ํ์์ ๋, ํ๋ฐํธ๋ก ๋ฆฌ๋ค์ด๋ ํธ๊ฐ ํ์ํ์๋ค. ์ด ๋์๋ ์ง์ URI๋ฅผ ๋น๋ํ์ฌ ๋ฆฌ๋ค์ด๋ ํธ๋ฅผ ์์ผ์ฃผ์๋ค. ํ์ง๋ง ์ด ๋ถ๋ถ์์๋ ์กฐ๊ธ ์์ฌ์ด ์ ์ด ์์๋ค. ๋ฐ๋ก ํ๋ผ๋ฏธํฐ๋ก ํ ํฐ์ ์ ๋ฌํ๋ ๋ถ๋ถ์ด๋ค. HttpHeaders()๋ฅผ ์ด์ฉํ์ฌ ํค๋์ ์ถ๊ฐํ๊ณ ๋ฆฌ๋ค์ด๋ ํธ๋ฅผ ํด๋ณด์๋๋ฐ, ํค๋๋ก ์ ์๋ ์ ๊ฐ๋ ๊ฒ์ผ๋ก ํ์ธ์ด ๋์๋ค. ๊ทธ๋์ ํ๋ผ๋ฏธํฐ๋ก ๋์ง๊ฒ ๋์๋ค. ๋ง์ง๋ง์ ์๊ฐ์ด ๋ชจ์๋ ์ํฉ์ด์์ด์ ๋ ์์๋ณด์ง ๋ชปํ๊ณ ์ด๋ ๊ฒ ์ฒ๋ฆฌํ ์ ๋ฐ์ ์์๋ ๊ฒ์ด ๋๋ฌด ์์ฌ์ ๋ค. ๊ทธ๋๋ ๊ฐ์ธ์ ์ผ๋ก ๋ฟ๋ฏํ ๊ฒ์, ์ต์ด ์์ ๋ก๊ทธ์ธ ์ ์ญํ ์ ์ ํํ ์ ์๋๋ก ์ค๊ณํ ๋ถ๋ถ์ด๋ค. ์๋น์ค ํน์ฑ์ ์๋น์์ ์์ฐ์๊ฐ ๋๋์๋ค. ๊ทผ๋ฐ ์์ ๋ก ๋ค์ด์ค๋ฉด ์ด๋ป๊ฒ ์ ํํด์ผํ ์ง ์ด๋ ค์ ๋ค ์ด๊ฒ์ ๋ฆฌ๋ค์ด๋ ํธ ๊ณผ์ ์์ ํ๋ฐํธ ๋ถ๊ป์ ํด๋น ์ ํ ํ์ด์ง์์ ์ญํ ์ ์ ํํ๊ฒ ํ์ฌ ํด๋น ์์ฒญ์ด ์๋ฒ๋ก ๋ค์ด์ค๋ฉด ํด๋น ์ญํ ์ ๋ง์ถ์ด ํ ํฐ์ ๋ค์ ์ฌ๋ฐ๊ธํ์ฌ ๋ค์ ํ๋ฐํธ์ ์ ๋ฌํด์ฃผ์๋ค. ๊ทธ๋ฆฌ๊ณ ์ด ํ์ด์ง๋ ์ต์ด ์์ ๋ก๊ทธ์ธ์๋ง ์ ์ฉํ ์ ์๊ฒ ํ์๋ค. ์ด ๋ถ๋ถ์ ์ฌ์ค ๋ ์ง ๋ชฐ๋๋๋ฐ ๊ตฌํํ ์ ์๊ฒ ๋์ด ๊ต์ฅํ ๋ฟ๋ฏํ๋ค!
๐ฉ๐ป๐พ ํ ํฐ์ ์ด์ฉํ์ฌ ์ ์ ๊ถํ ํ๋ณ
- ํค๋์ ๋ค์ด์ค๋ ํ ํฐ์์ ํด๋นํ๋ ๊ถํ์ ๊ฐ์ง ์ ์ ๊ฐ ๋ง๋์ง ํ์ธ
- Security FilterChain์ ๋ฉ์๋๋ฅผ ์ด์ฉํ์ฌ ๊ตฌํ
- ํ๋ก์ ํธ ์ดํ ๋๋ฐธ๋กญ : ๋ช ์์ ์ผ๋ก ํ๋์ฉ ์ ์ ๋ถ๋ถ์ ํฉ์ณ์ ์ ๊ธฐ
: FilterChain์ authorizeHttpRequests()๋ฅผ ์ด์ฉํ์ฌ uri์ method๋ฅผ ๋น๊ตํ์ฌ ๊ถํ์ ์ ๋๋ก ๊ฐ์ง๊ณ ์๋์ง ํ๋ณํ์๋ค. ๋ชจ๋๊ฐ ์ ๊ทผํด์ผํ๋ ๋ถ๋ถ๊ณผ ๊ถํ๋ณ๋ก ์ ๊ทผํด์ผํ๋ ๋ถ๋ถ์ ๋๋์๋ค. ๋ช ์์ ์ผ๋ก ํ๋์ฉ ์ ์ด์ฃผ์๋๋ฐ, ํ๋์ฉ ํ์ธํ๊ธฐ ์ํด์ ์ ์๋ค. ์ดํ ํ๋ก์ ํธ๊ฐ ๋๋๊ณ ๋ ํด๋น ๋ถ๋ถ์ ๋ชจ์์ ์ฒ๋ฆฌํด ๋ณผ ์๊ฐ์ด๋ค. ์๋ํ๋ฉด, ์์ ์๋ ์์๋ณ๋ก ๊ฑธ๋ฌ์ง๊ธฐ ๋๋ฌธ์ ์ฌ๋ฌ๊ฐ์ง ๋ฌถ์ ๋ ๊ทธ๊ฒ์ ๊ณ ๋ คํด์ ๋ฌถ์ด๋ด์ผ ํ๊ธฐ ๋๋ฌธ์ด๋ค. ํ๋์ฉ ์์ ๋์๋ ๊ทธ ๋ถ๋ถ์ด ์กฐ๊ธ์ ์์ํ๊ธฐ ๋๋ฌธ์ด๋ค.
์๋๋ ์๋ ์ค๋นํ๋ ํผํผํฐ์ ์ผ๋ถ์ด๋ค. ๋ง์ฝ ์ ์ ๊ถํ์ด ํ์ํ ๊ฒฝ์ฐ ์๋์ฒ๋ผ ํ๋ฌ๊ฐ๋ค.
๐ฉ๐ป๐พ ํ์ CRUD ๊ตฌํ
- ํ์ ๊ด๋ฆฌ ๋ก์ง CRUD ๊ตฌํ
- ํ์ ๊ฐ์ ์ ํ์ ๋ฉ์ผ ๋ฐ์ก
- ํ๋ก์ ํธ ์ดํ ๋๋ฐธ๋กญ : ์ด๋ฉ์ผ ์ธ์ฆ ๊ตฌํ ํน์ ๋น๋ฐ๋ฒํธ ์ฐพ๊ธฐ ๊ตฌํ
: ๋ก๊ทธ์ธ์ ์ฐ๊ฒฐ๋์ด ํ์ ํ ์ด๋ธ์ ๋งก์์ ๊ตฌํํ์๋ค. ํ์ ๊ฐ์ ๋ฐ ์์ , ์กฐํ, ์ญ์ ์ ๊ธฐ๋ณธ CRUD๋ฅผ ๊ตฌํํ์๋๋ฐ, ์ ๊ณผ ๋ค๋ฅธ ์ ์ด ์๋ค๋ฉด ํ์ ํ ์ด๋ธ์ด ์ธ ๊ฐ๋ก ๋๋๋ค๋ ์ ์ด์๋ค. ๊ณตํต์ ํ์ ํ ์ด๋ธ์ด ์๊ณ , ์์ฐ์์ ์๋น์์ ํ ์ด๋ธ์ ๋๋์ด ๊ตฌํํ์๋ค. ์ฌ์ค ์ด๋ฒ ๋ก์ง์์๋ ๋ง์ด ๋ค๋ฅธ๊ฒ ์กด์ฌํ์ง ์์์ง๋ง, ๊ธฐ๋ฅ์ด ๋ง์์ง ์๋ก ๋๋์ด ๊ตฌ์ฑํ๋ ๊ฒ ์ข๋ค๊ณ ์ ์ ๋ฉํ ๋๊ป์ ์กฐ์ธ์ ํด์ฃผ์ ์ ์ด ์๋ค. ๊ทธ๋์ ์ด๋ฒ ๊ฒฝํ์ด ์ข์๋ค. ๊ทธ๋์ ์ํฐํฐ๋ ๋๋๊ณ ์๋น์ค๋ ์ปจํธ๋กค๋ฌ๋ ๊ธธ์ด์ง์ง ์๊ฒ ๋๋์ด์ ๊ตฌํํ์๋ค.
๐ฉ๐ป๐พ ์ฐ๊ด ๊ด๊ณ
- ํ ์ด๋ธ ๊ฐ์ ์ฐ๊ด ๊ด๊ณ ์ฐ๊ฒฐ
- ์๋ฐฉํฅ ์ฐ๊ฒฐ์ ์ํ ์ฐ๊ด ๊ด๊ณ ํธ์ ๋ฉ์๋ ๊ตฌํ
- ํ๋ก์ ํธ ์ดํ ๋๋ฒจ๋กญ : ๋ ํจ์จ์ ์ธ ์ฐ๊ด ๊ด๊ณ๋ฅผ ์๊ฐํด ๋ณผ ๊ฒ
: ์์ ์ฐ๊ฒฐํด์ ์ํฐํฐ ๊ฐ์ ์ฐ๊ฒฐ๊ด๊ณ๋ฅผ ์ค์ ํด์ฃผ์๋ค. ์ฐ๊ด ๊ด๊ณ๋ฅผ ์ ๋๋ก ํ์ง ์์ผ๋ฉด ์ญ์ ํ ๋์ ๋ฌธ์ ๊ฐ ์๊ธด๋ค. ์ด๋ฒ์ ํ๋ก์ ํธ๋ฅผ ํ๋ฉด์ ๋ฆฌ๋ทฐ๋ ๋ฌธ์๊ฐ ์ ๋๋ก ์ญ์ ๊ฐ ์๋๋ฉด ํํด๊ฐ ์๋๋ ์๋ฌ๋ฅผ ๋ง๋ฌ์๋ค. ์ด์ ๋ ๋ฐ๋ก ํ ์ชฝ์๋ง ์ฐ๊ด๊ด๊ณ๋ฅผ ์ฃผ๊ฑฐ๋, ์๋ชป๋ ๋ฐฉ์์ผ๋ก ์ฐ๊ด ๊ด๊ณ์ ์์๋ ๋ถ๋ถ๋ค์ด ๋์ค์ ๋ฌธ์ ์ ์ผ๋ก ๋ฐ๊ฒฌ๋๋ ๊ฒ์ด์๋ค. ์ฌ์ค ๊ทธ๋์ ์ฐ๊ด๊ด๊ณ๋ ๊ทธ๋ฅ ์๋ก ์ฐธ์กฐํด์ ๊ฐ์ ธ์ค๋ ๊ฑฐ ์ ๋๋ก๋ง ํ๋จํ์๋๋ฐ, ์ด๋ฒ์ ์ ๋๋ก ์ํ๋ฉด ์ด๋ค ๋ฌธ์ ๊ฐ ๋ํ๋๋์ง ๋๋ฌด ๋ผ์ ธ๋ฆฌ๊ฒ ๋๊ผ๋ค. ER ๋ค์ด์ด๊ทธ๋จ๋ ์ฝ 5~6๋ฒ ์ ๋ ๊ณ ์น ๊ฒ ๊ฐ๋ค. ์ฒ์์ ์ ๋ง ์ฒ ์ ํ๊ฒ ํ๋ค๊ณ ํ๋๋ฐ, ํ๋ค๋ณด๋ ๋ฐ๋ ํ์๊ฐ ์๋ ๋ถ๋ถ๋ค์ด ๊ณ์ ๋ํ๋ฌ๋ค.
ํ๋ก์ ํธ๊ฐ ๋๋ฌ์ด๋ ์ด๊ฑฐ๋ณด๋ค ๋ ํจ์จ์ ์ธ ์ฐ๊ด๊ด๊ณ๊ฐ ์๋์ง ์๊ฐํด ๋ณด๊ณ ์ถ๋ค. ์๋ํ๋ฉด, ๊ทธ ์ด์ ๋ ์๋์ ๋ฆฌ๋ทฐ์ ์ค๋ช ํ๋ ค๊ณ ํ๋ค.
๐ฉ๐ป๐พ ๊ตฌ๋งค๋ฅผ ํ ํ์๋ง ๋ฆฌ๋ทฐ ์์ฑ
- ์ฟผ๋ฆฌ๋ฅผ ์ด์ฉํ์ฌ ์ฐ๊ด ๊ด๊ณ์ ์๋ Client๋ก 1์ฐจ ์ฃผ๋ฌธ ๋ฆฌ์คํธ๋ฅผ ๊ฐ์ ธ์ด
- Stream์ ์ด์ฉํ์ฌ filter๋ก ์ฃผ๋ฌธ ๋ฆฌ์คํธ์ ์ํ ์์ด๋์ ๋ฆฌ๋ทฐ๋ฅผ ์ฐ๋ ค๋ ๊ณณ์ ์ํ ์์ด๋๊ฐ ์ผ์นํ๋ ์ง ํ๋ณ
- ๋ค์์ผ๋ก ๊ฑธ๋ฌ์ง ์ฃผ๋ฌธ ๋ฆฌ์คํธ์์ ๊ฒฐ์ ์๋ฃ๊ฐ ์กด์ฌํ๋์ง ํ๋ณ
- ํ๋ก์ ํธ ์ดํ ๋๋ฐธ๋กญ : ์ผ๋์ผ ์ฐ๊ด๊ด๊ณ๋ก๋ ํ ๋ฒ ํด๋ณด๊ธฐ
: ์ฐ๋ฆฌ ์๋น์ค๋ ๋ฆฌ๋ทฐ๊ฐ ํด๋น ๊ธ ๊ฒ์ํ ์๋์์ ์์ฑํ๋ค. ์์ ER ๋ค์ด์ด๊ทธ๋จ์ฒ๋ผ ์ฐ๊ด ๊ด๊ณ์์ ๋ฆฌ์คํธ๋ก ์ด์ฉํ ์ ๋ฐ์ ์์๋ค. ๋ง์ฝ ์ฃผ๋ฌธ ๋ด์ญ์์ ์์ฑํ๋ค๋ฉด ์ผ๋์ผ๋ก ๊ฐ๋ฅํ์ ๊ฒ์ด๋ค. ๊ทธ๋์ ์ด ๋ถ๋ถ๋ ํ ๋ฒ ๊ตฌํํด๋ณด๋ ค๊ณ ํ๋ค. ํ์คํ ์ผ๋์ผ๋ก ํ๋ค๋ฉด ํด๋น ์ฃผ๋ฌธ์ ์ ๋๋ก ๊ฐ์ง๊ณ ์ฌ ์ ์์ ๊ฒ ๊ฐ๋ค. ๋ง์ฝ ์ฝ๋๊ฐ ๊ถ๊ธํ๋ค๋ฉด ์๋์ ๊ธ์ ์ดํด๋ณด๋ ๊ฒ์ ์ถ์ฒํ๋ค.
๐ฉ๐ป๐พ ๋ฆฌ๋ทฐ ์ญ์ ์ ๊ฒ์ํ์ ํ์ ๊ณผ ๋ฆฌ๋ทฐ ๊ฐ์ ๋ณํ ๊ตฌํ (+ ํธ๋์ญ์ ๋ฌธ์ )
- ๋ฆฌ๋ทฐ๋ฅผ ์ญ์ ํ๋ฉด ํ์ ๊ณผ ๋ฆฌ๋ทฐ ๊ฐ์๊ฐ ๋ณํด์ผ ํ๋ค.
- ๋ง์ฝ ๋ฆฌ๋ทฐ๊ฐ 1๊ฐ์ด๋ฉด, ๋ ํฌ์งํ ๋ฆฌ ํด๋์ค์ ์ฟผ๋ฆฌ๋ฌธ์ผ๋ก ๊ฐ์ ธ์ค์ง ๋ชปํ๋ ์์๋ก ์ง์ ํด์ค๋ค.
- ๊ทธ๋ฆฌ๊ณ ๋ฆฌ๋ทฐ ๊ฐ์์ ํ์ ์ ๋ค์ ์ ๋ฆฌํด์ค๋ค.
- โญ๏ธ ํธ๋์ญ์ ๋ ์ด๋ ธํ ์ด์ ์ด ์์ด์ผ ํ๋ค. ์์ผ๋ฉด ๋กค๋ฐฑ์ด ๋์ด ์ง์์ง์ง ์๋ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ค. โญ๏ธ
- ํ๋ก์ ํธ ์ดํ ๋๋ฐธ๋กญ : ํธ๋์ญ์ ๊ณต๋ถ ๋ฐ ์ ๋ฆฌ
: ํธ๋์ญ์ ์ ์ด๋ฒ ํ๋ก์ ํธ์ ๊ฝ์ด์๋ค. ์ด๋ค ์๋น์ค๋ ํธ๋์ญ์ ์ด๋ ธํ ์ด์ ์ ๋ถ์ด์ง ์์์ ์ค๋ฅ๊ฐ ๋ฐ์ํ๊ณ , ์ด๋ค ์๋น์ค๋ ๋ถ์ฌ์ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ค. ์ด๋ ๊ฒ ๋ณํ๋ฅผ ์ค์ผํ๋ ๋ฉ์๋์ @Transactional ์ด๋ ธํ ์ด์ ์ ์๋ชป ๋ถ์ด๋ฉด ๋ณํ๊ฐ ์๊ธฐ์ง ์์๊ณ , ๋ฉ์๋ ์์ ๋ก์ง๋ค์ด ํ๋๋ก ๊ฐ์ผ ํ๋ ๋ถ๋ถ์ @Transactional ์ด๋ ธํ ์ด์ ์ ๋ถ์ด์ง ์์ผ๋ฉด ํ๋๋ ์ผ์ด๋๊ณ ํ๋๋ ์ผ์ด๋์ง ์๋ ์๋ฌ๊ฐ ๋ฐ์ํ๋ค.
์ฒซ ๋ฒ์งธ์ ๊ฒฝ์ฐ์ ์๋ฌ๋ ์ด ํ์ ๊ณผ ๋ฆฌ๋ทฐ ๋ณํ์ OrdService์์ ์ฃผ๋ฌธ์ ์ฃผ๋ฌธ ์ํ๊ฐ ์ฃผ๋ฌธ ์๋ฃ์์ ๊ฒฐ์ ์๋ฃ๋ก ๋ฐ๋๋ ๋ถ๋ถ์์ ๊ฒฝํํ์๋ค. ํ์ ๊ณผ ๋ฆฌ๋ทฐ ๋ณํ์์๋ ๋ฆฌ๋ทฐ๊ฐ ์ญ์ ๋์ง ์๊ณ ๊ณ์ DB์ ๋จ๋ ์ค๋ฅ๊ฐ ๋ฐ์ํ๊ณ , ์ฃผ๋ฌธ ์๋น์ค์์ ์ํ๋ฅผ ๋ณํํ ๋์๋ ์ํ๊ฐ ๊ณ์ ๋ณํ์ง ์๋ ์ค๋ฅ๋ฅผ ๊ฒช์๋ค. ๋ฐ๋๋ก ๋ ๋ฒ์งธ์ ๊ฒฝ์ฐ์ ์์๋ Board์ Product์๋ค. ์ฐ๋ฆฌ ๋ก์ง์์๋ ๋ ํ ์ด๋ธ์ด ์ผ๋์ผ๋ก ์ฐ๊ด์ด ๋์ด์๊ณ , ๊ฒ์ํ์ ๋ฑ๋กํ ๋์ ์ํ์ด ๋ฑ๋ก๋๊ธฐ ๋๋ฌธ์ ์์ด๋๊ฐ ๋๊ฐ์์ผ ํ๋ค. ํ์ง๋ง ์ด๋ ์๊ฐ ๊ฒ์ํ๊ณผ ์ํ์ ์์ด๋๊ฐ ๋ค๋ฅด๊ฒ ๊ฐ๋ ๊ฒ์ด์๋ค. ์ด์ ๋ ๋ฐ๋ก ์ด @Transactional์ด ์์ด์์๋ค. ํด๋น ๋ถ๋ถ์ด ์์ด์ ํธ๋์ญ์ ์ ์์์ฑ๊ณผ ๊ฒฉ๋ฆฌ์ฑ์ด ๋ณด์ฅ๋์ง ๋ชปํ์๋ค. ๋๋ฌธ์ ์ฌ๋ฌ๋ช ์ด ๋ฑ๋กํ๋ฉด ๋ ์์ด๋๊ฐ ๊ผฌ์ธ ๊ฒฝํ, Board์์ ์๋ฌ๊ฐ ๋ฐ์ํด ๋ฑ๋ก๋์ง ์์์์๋ Product๋ง ๋ฑ๋ก๋๋ ๊ฒฝํ์ ํ์๋ค.
๊ทธ๋์ ํธ๋์ญ์ ์ ๋ํด์ ์กฐ๊ธ ๋ ๋ง์ ๊ณต๋ถ๊ฐ ํ์ํ๋ค๋ ๊ฒ์ ๋๊ผ๋ค.
ํด๋น ์๋ฌ์ ๊ฒฝํ์ ์๋ ๋ธ๋ก๊ทธ์ ์งง๊ฒ ์จ์๋ค.
๐ฉ๐ป๐พ ํ ํฐ ์ฌ๋ฐ๊ธ ๊ตฌํ
- ์์ธ์ค ํ ํฐ ํน์ ๋ฆฌํ๋ ์ ํ ํฐ ๋ง๋ฃ ์ ์ฌ๋ฐ๊ธ ํ ์ ์๋๋ก ๊ตฌํ
- AOP, REST API๋ก ๊ตฌํ
- ํ๋ก์ ํธ ์ดํ ๋๋ฐธ๋กญ : ๋ค๋ฅธ ํจ์จ์ ์ธ ๋ฐฉ๋ฒ์ ์๊ฐํด ๋ณผ ๊ฒ
: JWT ํ ํฐ์ ์ด์ฉํด ๋ก๊ทธ์ธ์ ๊ตฌํํ๋ค๋ณด๋ ์์ฐ์ค๋ฝ๊ฒ ํ ํฐ์ ๋ง๋ฃ์๊ฐ์ ์๊ฐํ๊ฒ ๋์๋ค. ๊ทธ๋์ ์ด ๋ง๋ฃ๋ฅผ ์ด๋ป๊ฒ ๊ตฌํํ ์ง ์๊ฐํด๋ณด์๋ค. ๋ฐฉ๋ฒ์ ๋ ๊ฐ์ง๋ก ๊ตฌํํด๋ณด์๋ค. ์ฒซ ๋ฒ์งธ ๋ฐฉ๋ฒ์ ๋ด๊ฐ ํด๋ผ์ด์ธํธ์๊ฒ ๋ง๋ฃ๊ฐ ๋์์์ ์๋ฆฌ๋ฉด ํด๋ผ์ด์ธํธ๊ฐ ์ฌ๋ฐ๊ธ ์๋ํฌ์ธํธ๋ก ์ฌ๋ฐ๊ธ ์์ฒญ์ ๋ณด๋ด๋ ๊ฒ์ด๋ค. ๋ ๋ฒ์งธ๋ AOP๋ก ํ ํฐ์ด ๋ค์ด์ฌ ๋๋ง๋ค ๊ฒ์ฌํด์ ๋ง๋ฃ ์๊ฐ์ด ์๋ฐํ์ผ๋ฉด ์๋์ผ๋ก ์ฌ๋ฐ๊ธ ํด์ ๋ค์ ํค๋์ ๋ด์ ๋๋๋ ค ์ฃผ๋ ๊ฒ์ด๋ค. ์ฒซ ๋ฒ์งธ ๋ฐฉ๋ฒ์ ์์ ๋ฐฉ๋ฒ์ด๋ค. ์์ธ์ค ํ ํฐ์ ์ฌ ๋ฐ๊ธ ํ๊ณ , ๋ง์ฝ ๋ฆฌํ๋ ์ ํ ํฐ์ ์๊ฐ์ด ํ๋ฃจ ์ดํ๋ก ๋จ์๋ค๋ฉด ์ฌ๋ฐ๊ธ ํด์ ๋ฆฌํ๋ ์ ํ ํฐ์ ์ ๋ฐ์ดํธํด์ ์ ์ฅ์์ ์ ์ฅํ๋ค.
@Transactional
public TokenDto reissueRefresh(HttpServletRequest request, HttpServletResponse response) {
/* Access Token ํ์ธ */
String accessToken = request.getHeader("Authorization").replace("Bearer ","");
if (!securityProvider.validate(accessToken)) {
log.error("์ ํจํ์ง ์์ access token");
throw new BusinessLogicException(ExceptionCode.UNAUTHORIZED_TOKEN);
}
Map<String, Object> claims = securityProvider.parseClaims(accessToken);
if (claims == null) {
throw new BusinessLogicException(ExceptionCode.NOT_EXPIRATION_TOKEN);
}
/* Refresh Token ํ์ธ */
String username = (String)claims.get("username");
String refreshToken = CookieUtil.getCookie(request, "Refresh")
.map(Cookie::getValue)
.orElseThrow(() -> new BusinessLogicException(ExceptionCode.LOGOUT_MEMBER));
RefreshToken userRefreshToken =
refreshTokenRepository.findByKey(username)
.orElseThrow(() -> new BusinessLogicException(ExceptionCode.LOGOUT_MEMBER));
if (securityProvider.validate(refreshToken)) {
log.error("์ ํจํ์ง ์์ refresh token");
throw new BusinessLogicException(ExceptionCode.UNAUTHORIZED_TOKEN);
}
long now = (new Date()).getTime();
long validTime = securityProvider.getTokenClaims(refreshToken).getExpiration().getTime() - now;
/* ๋ฆฌํ๋ ์ ํ ํฐ์ด ํ๋ฃจ ์ด๋ด๋ก ๋จ์๋ค๋ฉด, ์ฌ ๋ฐ๊ธ (์์ธ์ค ํ ํฐ๋ ๊ฐ์ด ์ฌ๋ฐ๊ธ) */
if (validTime <= 1000 * 60 * 60 * 24) {
TokenDto tokenDto = securityProvider.generatedTokenDto(username);
accessToken = tokenDto.getAccessToken();
refreshToken = tokenDto.getRefreshToken();
/* Refresh DB update */
userRefreshToken.updateValue(refreshToken);
refreshTokenRepository.saveAndFlush(userRefreshToken);
int cookieMaxAge = (int) 1000 * 60 * 24 * 7;
CookieUtil.deleteCookie(request, response, "Refresh");
CookieUtil.addCookie(response, "Refresh", refreshToken, cookieMaxAge);
}
/* ๋ฆฌํ๋ ์ ํ ํฐ์ด ์ ํจํ๋ฐ ๋ณด๋ธ ์ค์ ์ด๊ธฐ์ ์์ธ ๋์ง๊ธฐ */
log.error("refresh token ์ด ๋ง๋ฃ๋์ง ์์์ต๋๋ค.");
throw new BusinessLogicException(ExceptionCode.NOT_EXPIRATION_TOKEN);
}
๋ ๋ฒ์งธ ๋ฐฉ๋ฒ์ ์๋์ ๋ฐฉ๋ฒ์ด๋ค. ๋จผ์ ์ด๋ ธํ ์ด์ ์ ํ๋ ๋ง๋ค๊ณ , Aspect ์ด๋ ธํ ์ด์ ์ผ๋ก AOP๋ฅผ ์ฒ๋ฆฌ๋ฅผ ํด์ค๋ค. ๊ทธ๋ฆฌ๊ณ ํ ํฐ์ด ๋ค์ด์ค๋ฉด ํด๋น ํ ํฐ์ ์ ํจ์๊ฐ์ ํ์ธํด์ ์ ํจ์๊ฐ์ด ์๋ฐํ๋ฉด ์ฌ๋ฐ๊ธ์ ํด์ ํค๋์ ๋๊ฒจ์ค๋ค. ๋ฆฌํ๋ ์ ํ ํฐ๋ ์ ํจ์๊ฐ์ด ์๋ฐํ๋ฉด ์ ๋ฐ์ดํธํด์ ์ ์ฅ์์ ์ ์ฅํ๋ค.
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ReissueToken {
}
@Aspect
@Component
@Slf4j
@RequiredArgsConstructor
public class SecurityAspect {
private final SecurityProvider securityProvider;
private final RefreshTokenRepository refreshTokenRepository;
@Before("@annotation(reissueToken)")
public void getAccessTokenAgain(ReissueToken reissueToken) throws Throwable {
log.info("# ์ด๋
ธํ
์ด์
ํ ํฐ ์ ํจ์ฑ ๊ฒ์ฌ ์์");
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
HttpServletResponse response = requestAttributes.getResponse();
String accessToken = request.getHeader("Authorization").replace("Bearer ", "");
Authentication authentication = securityProvider.getAuthentication(accessToken);
RefreshToken refreshTokenTable = refreshTokenRepository.findByKey(authentication.getName())
.orElseThrow(()-> new BusinessLogicException(ExceptionCode.NOT_FOUND_TOKEN));
String refreshToken = refreshTokenTable.getValue();
if (accessToken == null) {
log.error("์์ธ์ค ํ ํฐ์ ์ฐพ์ ์ ์์ต๋๋ค.");
throw new BusinessLogicException(ExceptionCode.NOT_FOUND_TOKEN);
}
/* ํ ํฐ ์ ํจ ์๊ฐ */
Date now = new Date();
long accessValidTime = securityProvider.getTokenClaims(accessToken).getExpiration().getTime() - now.getTime();
long refreshValidTime = securityProvider.getTokenClaims(refreshToken).getExpiration().getTime() - now.getTime();
/* ์์ธ์ค ํ ํฐ์ ์๊ฐ์ด 10๋ถ ์ด๋ด๋ก ๋จ์๋ค๋ฉด ์ฌ ๋ฐ๊ธ */
if (accessValidTime <= 1000 * 60 * 10) {
log.info("# ์์ธ์ค ํ ํฐ ์ฌ ๋ฐ๊ธ");
String role = authentication.getAuthorities().toString().replace("[ROLE_","").replace("]", "");
Date newAccessExpiration = new Date(now.getTime() + securityProvider.getAccessTokenTime());
accessToken =
securityProvider.createAccessToken(authentication.getName(), role, newAccessExpiration);
}
/* ๋ฆฌํ๋ ์ ํ ํฐ์ ์๊ฐ์ด ํ๋ฃจ ์ด๋ด๋ก ๋จ์๋ค๋ฉด ์ฌ ๋ฐ๊ธ */
if (refreshValidTime <= 1000 * 60 * 60 * 24) {
log.info("# ๋ฆฌํ๋ ์ ํ ํฐ ์ฌ ๋ฐ๊ธ");
Date newRefreshExpiration = new Date(now.getTime() + securityProvider.getRefreshTokenTime());
refreshToken = securityProvider.createRefreshToken(authentication.getName(), newRefreshExpiration);
refreshTokenTable.updateValue(refreshToken);
refreshTokenRepository.saveAndFlush(refreshTokenTable);
}
response.setHeader("Authorization", accessToken);
log.info("# ์ด๋
ธํ
์ด์
ํ ํฐ ์ ํจ์ฑ ๊ฒ์ฌ ์ข
๋ฃ ");
}
}
ํ๋ก์ ํธ๊ฐ ๋๋๊ณ ์ข ๋ ๊น๋ํ๊ฒ ์ฝ๋๋ฅผ ์ ๋ฆฌํด์ ์ ์ ์ ์๋๋ก ํด๋ด์ผ๊ฒ ๋ค.
๐ฉ๐ป๐พ ํ์ฌ ๋ก๊ทธ์ธํ ์ ์ ํ๋ณ
- ํ์ฌ ๋ก๊ทธ์ธํ ์ ์ ์ ์ ๊ทผํ๋ ค๋ ํ์ด์ง์ ์ ์ ๊ฐ ๊ฐ์์ง ํ๋ณ์ด ํ์
- ๊ณตํต์ ํด๋์ค๋ฅผ ๋ง๋ค๊ณ , ๋ฉค๋ฒ ์๋น์ค ๋จ์ ํด๋น ํด๋์ค๋ฅผ ์ด์ฉํ์ฌ ํ๋ณ ๋ฉ์๋ ์์ฑ
: ์ ๋ฒ ํ๋ฆฌ ํ๋ก์ ํธ ๋์๋ Principal ๊ฐ์ฒด๋ก ์ผ์ผ์ด ์ปจํธ๋กค๋ฌ์์ ์์ ์ ํด์ฃผ์๋ค. ๊ฐ์ธ์ ์ผ๋ก ๊ทธ๊ฒ ๊ต์ฅํ ํจ์จ์ ์ด์ง ๋ชปํ๋ค๋ ๊ฒ์ ๋๊ผ๋ค. ์๋ํ๋ฉด, ๊ฒฐ๊ตญ ๋น์ทํ ๋ก์ง์ ๋ฐ๋ณต์ด๊ธฐ ๋๋ฌธ์ด๋ค. ๊ทธ๋์ ์ด๊ฒ์ ์ด๋ป๊ฒ ํ๋ฉด ํจ์จ์ ์ผ๋ก ๋ถ๋ฌ์ค๊ณ ํ๋ณํ ์ ์์๊น ์๊ฐํด๋ณด์๋ค. ์ด๋ ๊ฒ ํ๋ณํ๋ ์ด์ ๋ ํด๋น ํ์ด์ง ์์ฒญ ๊ถํ์ ์ ๋ง ๊ถํ๋ง ๋ณด๊ธฐ ๋๋ฌธ์ด๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ์ด ํ์ด์ง์ ์ฃผ์ธ์ธ ์ ์ ๊ฐ ์๋์ด๋ ์ ๊ทผ์ด ๊ฐ๋ฅํ ์ ์๊ธฐ ๋๋ฌธ์ ๋ฐฑ์์๋ ๋ง์์ผ ํ๋ ๊ฒ์ด๋ค.
์๋์ฒ๋ผ SecurityUtil์ด๋ผ๋ ํด๋์ค๋ฅผ ๋ง๋ค์ด์คฌ๊ณ ContextHoder์์ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ ํ์ฌ ๋ก๊ทธ์ธ ํ ์ ์ ์ ์ด๋ฉ์ผ์ ๊ฐ์ ธ์ฌ ์ ์๋๋ก ๊ตฌํํ์๋ค. ์ฐ๋ฆฌ ๋ก์ง์์ ์ด๋ฉ์ผ์ ์์ด๋๋ก, ์ ๋ํฌํ ๊ฐ์ ์ง๋ ๊ธฐ ๋๋ฌธ์ด๋ค. ์์ฐ์์ ๊ฒฝ์ฐ ์์ฐ์ ๋ง์ดํ์ด์ง๋ฅผ ๋ชจ๋๊ฐ ์ ๊ทผํ ์ ์๊ณ , ์๋น์๋ ์์ ๋ง ์ ๊ทผ ํ ์ ์๋ค. ๊ทธ๋์ ์๋น์๋ ์๋น์ ์๋น์ค์ ๋ง๋ค๊ณ ์๋น์๋ฅผ ์ฐพ๋ ๋ฉ์๋์ ํด๋น ๋ฉ์๋๋ฅผ ์คํ์์ผ ์๋น์๋ฅผ ์ฐพ์ ๊ฒฝ์ฐ ์๋์ผ๋ก ์ฐพ์ ์ ์๋๋ก ์ค๊ณํ์๋ค. ๋ฐ๋ผ์ ์์ฐ์๋ ์์ฐ์ ์๋น์ค์ ๋ง๋ค๊ณ ํ์์ ๋ฐ๋ผ ๋ถ๋ฌ์ฌ ์ ์๋๋ก ํ์๋ค.
๊ฐ์ธ์ ์ผ๋ก ์ด๋ ๊ฒ ํ๋ ํจ์ฌ ํจ์จ์ ์ด์๋ ๊ฒ ๊ฐ๋ค๊ณ ์๊ฐํ๋ค.
public class SecurityUtil {
private SecurityUtil() {}
public static String getCurrentEmail() {
/* ContextHolder ์์ ์ ๋ณด ๊ฐ์ ธ์ค๊ธฐ */
final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null || authentication.getName() == null) {
throw new RuntimeException("ํด๋นํ๋ ์ธ์ฆ ์ ๋ณด๊ฐ ์กด์ฌํ์ง ์์ต๋๋ค.");
}
return authentication.getName();
}
}
/* ์๋น์ ์กฐํ */
@Transactional(readOnly = true)
public Client findClient(long clientId) {
correctClient(clientId);
Client client = findVerifiedClient(clientId);
return client;
}
/* ๋ก๊ทธ์ธ ํ ์ฌ์ฉ์์ ์ ๊ทผ ์ฌ์ฉ์ ํ๋ณ */
public void correctClient(long accessId) {
String email = SecurityUtil.getCurrentEmail();
Member loginMember = memberService.findMemberByEmail(email);
log.info("๋ก๊ทธ์ธํ ์ ์ : {}", loginMember.getName());
if (loginMember.getClient().getClientId() != accessId) {
throw new BusinessLogicException(ExceptionCode.WRONG_ACCESS);
}
}
/* ๋ก๊ทธ์ธ ํ ์ฌ์ฉ์์ ์ ๊ทผ ์ฌ์ฉ์ ํ๋ณ */
public void correctSeller(long accessId) {
String email = SecurityUtil.getCurrentEmail();
Member loginMember = memberService.findMemberByEmail(email);
log.info("๋ก๊ทธ์ธํ ์ ์ : {}", loginMember.getName());
if (loginMember.getSeller().getSellerId() != accessId) {
throw new BusinessLogicException(ExceptionCode.WRONG_ACCESS);
}
}
๐ฉ๐ป๐พ ์นด์นด์ค ํ์ด ๊ตฌํ
- ์นด์นด์ค ํ์ด API๋ฅผ ์ด์ฉํ ๊ฒฐ์ ๊ตฌํ
- ํ๋ก์ ํธ ์ดํ ๋๋ฐธ๋กญ : ๋ค๋ฅธ PG์ฌ ํ์ธํด๋ณด๊ธฐ
: ์ด๋ฒ ํ๋ก์ ํธ์์ ๊ฐ์ฅ ํด๋ณด๊ณ ์ถ์๋ ๋์ ์ธ ๋ถ๋ถ์ด์๋ค. ๊ทธ๋์ ์ธ ํ์ ๋ชจ๋ ํด๋ณด๊ณ ๊ฐ์ฅ ๋จผ์ ๋๋ ํ์์ ์ฝ๋๋ฅผ ์ปค๋ฐํ๊ธฐ๋ก ํ๋ค. ๊ทธ๋์ ๋๋ ๊ฐ์ด ๊ตฌํ์ ํด๋ณด์๋ค. ์นด์นด์ค ํ์ด API๋ ์นด์นด์ค ๋ฌธ์๋ก ๊ต์ฅํ ์ ์ ๋ฆฌ๋์ด ์์๊ณ , ํด๋น ๋ฌธ์ ๋๋ถ์ ์กฐ๊ธ ๋ ์์ํ๊ฒ ํ ์ ์์๋ค. ๊ทธ๋ฆฌ๊ณ ํ๋ฉด์ ์ฒ์ ๊ตฌํํด ๋ณธ ํํธ์ง๋ง ๊ต์ฅํ ์ ๊ธฐํ๊ณ ์ฌ๋ฐ์๋ค. ๋ํ ๊ธฐ๋ฅ์ ๊ตฌํํจ์ ์์ด์ ์ ๋ฆฌ๊ฐ ํ์ํ๋ค๊ณ ํ๋จ์ด ๋์ด ์ด ํํธ๋ ์ฌ๊ธฐ๋ค ์ ๋ฆฌํ๋ ๊ฒ์ด ์๋ ๋ฐ๋ก ํฌ์คํ ์ ํ๋ ๊ฒ ์ข์ ๊ฒ ๊ฐ๋ค๊ณ ์๊ฐ์ด ๋ค์๋ค.
+ ํฌ์คํ ์๋ฃ
๋์๋ณด๊ธฐ
: ์ด๋ฒ ๋ฉ์ธ ํ๋ก์ ํธ ๋์๋ ํ๋ฆฌ ๋ ๋ณด๋ค ๋ ๋ฐ์ ํ๊ณ ์ถ์๋ค. ๊ทธ๋์ ํ์ ๋ถ๋ค๊ณผ ์์ฌ๋ ๋ด๋ณด๊ณ ๋ฌธ์ ๊ฐ ์๊ธฐ๋ฉด ๊ฐ์ด ํด๊ฒฐํ๊ธฐ๋ ํ์๋ค. ๊ทธ๋์ ์ ์ฒด์ ์ธ ์ฝ๋์ ํ๋ฆ๋ ๊ทธ๋๋ ์ดํดํ ์ ์์๊ณ , ๋๋ถ์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ฉด ๊ฐ์ด ํด๊ฒฐํ ์๋ ์์๋ค. ๊ทธ๋ฆฌ๊ณ ๊ตณ์ด ์์ฌ๋ด์ง ์์๋ ๋์ง๋ง ํด๋ณด๊ณ ์ถ์ ๋ถ๋ถ๋ค์ ๊ณ์ํด์ ์ถ๊ฐํด๋๊ฐ๋ค. ๋๋ฌธ์ ๋ง์ด ์ฑ์ฅํ์ง ์์์๊น ์กฐ๊ธ์ ๊ธฐ๋๊ฐ ๋๋ค.
๋น์ฅ ์์ฒญ๋ ์ค๋ ฅ์๋ ์๋์ง๋ง, ๊ทธ๋๋ 4๊ฐ์์ ๊ณผ์ ์์ ๋น ๋ฅด๊ฒ ์ง๋๊ฐ๋ ๋ถ๋ถ๋ค์ ๋ํด์ ์ ๋ณด๋ค๋ ์ดํด๊ฐ ๋ง์ด ๋๊ณ , ํ๋ฆ๋ ๋ณด์ด๊ณ , ๋ด๊ฐ ์ด๋ ์ ๋๋ ์ค๋ช ํ ์ ์์ง ์๋ ํ๋ ์๊ฐ์ด ๋ค์๋ค. ๊ทธ๋ฆฌ๊ณ ๊ฐ์ธ์ ์ผ๋ก ๋์๊ฒ ์์ฌ์ ๋ ๋ถ๋ถ๋ค์ด ์์๋๋ฐ, ์๊ฐ๋ณด๋ค ๋ด๊ฐ ์ผ์ ๊ด๋ฆฌ๋ฅผ ๋๋ฌด ๋ฌํํ๊ฒ ํ ๋ถ๋ถ์ด ์์๋ค. ๊ทธ๊ฒ ๋์ค์๋ ๋ชฐ์์ณ์ ์กฐ๊ธ ์ด๋ ค์ ๋ ๊ฒ ๊ฐ๋ค. ์กฐ๊ธ์ฉ ๋๋์ด ๋ถ๋ฐฐํ๋ ์คํฌ์ ํค์์ผ๊ฒ ๋ค. ๊ทธ๋ฆฌ๊ณ Stream์ด๋ ์ฌ๋ฌ ๋ค๋ฅธ ๋ฐฉ์์ ์ฐพ์๋ณผ ๋, ์ผ๋ง๋ ๊ธฐ์ด๊ฐ ์ค์ํ์ง ๊ทธ๋ฆฌ๊ณ ์๊ณ ๋ฆฌ์ฆ์ด ์ค์ํ์ง๋ฅผ ๊นจ๋ฌ์๋ค. ๊ทธ๋์ ํด๋น ์คํฐ๋๋ฅผ ํ๋ ๋ง๋ค์ด์ ๊ณต๋ถํ๋ ค๊ณ ํ๋ค!
๋๊ธ