miniblog
Search
๋ณธ ํ๋ก์ ํธ๋ โ์คํ๋ง๋ถํธ 3 ๋ฐฑ์๋ ๊ฐ๋ฐ์ ๋๊ธฐโ ์์ ์ ์ฐธ๊ณ ํ์ฌ ์งํํ์์
OAuth ์ธ์ฆ ์ ์ฉ ์ํ ํ ์คํธ ์ฝ๋ ์์ฑ
โข
ํ
์คํธ์ฝ๋ ์์ - ๊ตต์ ๊ธ์จ๋ก ํ์ํ ๋ถ๋ถ ์ฐธ๊ณ
ํต์ฌ ์์ฝ
1.
์ฟ ํค๋ ์ฌ์ฉ์๊ฐ ์ด๋ ํ ์น์ฌ์ดํธ๋ฅผ ๋ฐฉ๋ฌธํ์ ๋, ๊ทธ ์น์ฌ์ดํธ๊ฐ ์ฌ์ฉํ๋ ์๋ฒ๋ฅผ ํตํด ๋ก์ปฌ์ ์ ์ฅ๋๋ ์์ ๋ฐ์ดํฐ์ด๋ค. ์ฟ ํค๋ ํค์ ๊ฐ์ผ๋ก ์ด๋ฃจ์ด์ ธ ์์ผ๋ฉฐ ๋ง๋ฃ ๊ธฐ๊ฐ, ๋๋ฉ์ธ ๋ฑ์ ์ ๋ณด๋ฅผ ๊ฐ์ง๊ณ ์๋ค.
2.
OAuth๋ ์ 3์ ์๋น์ค์๊ฒ ๊ณ์ ์ ๋งก๊ธฐ๋ ๋ฐฉ์์ด๋ค. OAuth ์์ ์ ๋ณด๋ฅผ ์ทจ๋ํ๋ ๋ฐฉ๋ฒ์ ๊ถํ ๋ถ์ฌ ์ฝ๋ ์น์ธ ํ์
, ์์์ ์น์ธ ํ์
, ๋ฆฌ์์ค ์์ ์ ์ํธ ์๊ฒฉ์ฆ๋ช
์น์ธ ํ์
, ํด๋ผ์ด์ธํธ ์๊ฒฉ์ฆ๋ช
์น์ธ ํ์
์ผ๋ก ๋๋๋ค.
3.
OAuth ๋ฐฉ์ ์ค ๊ถํ ๋ถ์ฌ ์ฝ๋ ์น์ธ ํ์
์ ํด๋ผ์ด์ธํธ๊ฐ ๋ฆฌ์์ค์ ์ ๊ทผํ๋ ๋ฐ ์ฌ์ฉ๋๋ฉฐ, ๊ถํ์ ์ ๊ทผํ ์ ์๋ ์ฝ๋๋ฅผ ์ ๊ณต๋ฐ์ผ๋ฉด ๋ฆฌ์์ค ์ค๋์ ๋ํ ์ก์ธ์ค ํ ํฐ์ ์ ๊ณต๋ฐ๊ฒ ๋๋ค.
18์ผ์ฐจ
๋ณธ ํ๋ก์ ํธ๋ โ์คํ๋ง๋ถํธ 3 ๋ฐฑ์๋ ๊ฐ๋ฐ์ ๋๊ธฐโ ์์ ์ ์ฐธ๊ณ ํ์ฌ ์งํํ์์
์คํ๋ง ์ํ๋ฆฌํฐ๋ก OAuth2๋ฅผ ๊ตฌํํ๊ณ ์ ์ฉํ๊ธฐ
โข
์คํ๋ง ์ํ๋ฆฌํฐ๋ฅผ ์ฌ์ฉํ์ฌ OAuth2 ๊ตฌํ ์์
โข
๊ฐ์ฅ ๋จผ์ ์ฟ ํค ๊ด๋ฆฌ ํด๋์ค๋ฅผ ๊ตฌํํ๊ณ , OAuth2์์ ์ ๊ณต๋ฐ์ ์ธ์ฆ ๊ฐ์ฒด๋ก ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค๋ ์ญํ ์ ํ๋ ์๋น์ค๋ฅผ ๊ตฌํํ๊ธฐ
โข
๊ธฐ์กด โ์ํ๋ฆฌํฐ ์ค์ ํ๊ธฐโ ์์ ๊ตฌํํ๋ WebSecurityConfig ํด๋์ค ๋์ ์ฌ์ฉํ OAuth2 ์ค์ ํ์ผ์ ๊ตฌํํ๊ธฐ
โข
๋ง์ง๋ง์๋ ์ง์ ํ
์คํธํ ์ ์๋๋ก ๋ทฐ๋ฅผ ๊ตฌ์ฑ
์์กด์ฑ ์ถ๊ฐ
โข
build.gradle
์ฟ ํค ๊ด๋ฆฌ ํด๋์ค ๊ตฌํ
OAuth2 ์ธ์ฆ ํ๋ก์ฐ๋ฅผ ๊ตฌํํ๋ฉฐ ์ฟ ํค๋ฅผ ์ฌ์ฉํ ์ผ์ด ์๊ธฐ๋๋ฐ ๊ทธ๋๋ง๋ค ์ฟ ํค๋ฅผ ์์ฑํ๊ณ ์ญ์ ํ๋ ๋ก์ง์ ์ถ๊ฐํ๋ฉด ๋ถํธํ๋ฏ๋ก ์ ํธ๋ฆฌํฐ๋ฅผ ์ฌ์ฉํ ์ฟ ํค ๊ด๋ฆฌ ํด๋์ค๋ฅผ ๋ฏธ๋ฆฌ ๊ตฌํํ๋ค.
17์ผ์ฐจ
๋ณธ ํ๋ก์ ํธ๋ โ์คํ๋ง๋ถํธ 3 ๋ฐฑ์๋ ๊ฐ๋ฐ์ ๋๊ธฐโ ์์ ์ ์ฐธ๊ณ ํ์ฌ ์งํํ์์
ํ ํฐ ๋ฐ๊ธ๋ฐ๊ธฐ
โข
๊ตฌ๊ธ ํด๋ผ์ฐ๋ ์ฝ์์ ์ ์ํ์ฌ ๊ตฌ๊ธ ํด๋ผ์ฐ๋ ์ฌ์ฉ ๋์ ์ ์ฐจ๋ฅผ ์งํํ ์ดํ์ ์ ํ๋ก์ ํธ ์์ฑํ๊ธฐ

โข
ํ๋ก์ ํธ ์ด๋ฆ ์ง์ ๋ค์์ ๋ง๋ค๊ธฐ ๋ฒํผ ํด๋ฆญ
16์ผ์ฐจ
๋ณธ ํ๋ก์ ํธ๋ โ์คํ๋ง๋ถํธ 3 ๋ฐฑ์๋ ๊ฐ๋ฐ์ ๋๊ธฐโ ์์ ์ ์ฐธ๊ณ ํ์ฌ ์งํํ์์
OAuth๋?
OAuth๋ ์ 3์ ์๋น์ค์ ๊ณ์ ๊ด๋ฆฌ๋ฅผ ๋งก๊ธฐ๋ ๋ฐฉ์์ด๋ค. ํํ ๋ณผ ์ ์๋ ๋ค์ด๋ฒ๋ก ๋ก๊ทธ์ธํ๊ธฐ, ๊ตฌ๊ธ๋ก ๋ก๊ทธ์ธํ๊ธฐ ๊ฐ์ ๊ฒ์ด๋ค.
โข
๋ฆฌ์์ค ์ค๋(resource owner)
โฆ
์์ ์ ์ ๋ณด๋ฅผ ์ฌ์ฉํ๋๋ก ์ธ์ฆ ์๋ฒ์ ํ๊ฐํ๋ ์ฃผ์ฒด์ด๋ค. ์๋น์ค๋ฅผ ์ด์ฉํ๋ ์ฌ์ฉ์๊ฐ ๋ฆฌ์์ค ์ค๋์ ํด๋น๋๋ค.
โข
๋ฆฌ์์ค ์๋ฒ(resource server)
โฆ
๋ฆฌ์์ค ์ค๋์ ์ ๋ณด๋ฅผ ๊ฐ์ง๋ฉฐ, ๋ฆฌ์์ค ์ค๋์ ์ ๋ณด๋ฅผ ๋ณดํธํ๋ ์ฃผ์ฒด๋ฅผ ์๋ฏธํ๋ค. ๋ค์ด๋ฒ, ๊ตฌ๊ธ, ํ์ด์ค๋ถ์ด ๋ฆฌ์์ค ์๋ฒ์ ํด๋นํ๋ค.
โข
์ธ์ฆ ์๋ฒ(authorization server)
โฆ
ํด๋ผ์ด์ธํธ์๊ฒ ๋ฆฌ์์ค ์ค๋์ ์ ๋ณด์ ์ ๊ทผํ ์ ์๋ ํ ํฐ์ ๋ฐ๊ธํ๋ ์ญํ ์ ํ๋ ์ ํ๋ฆฌ์ผ์ด์
์ ์๋ฏธํ๋ค.
โข
ํด๋ผ์ด์ธํธ ์ ํ๋ฆฌ์ผ์ด์
(client application)
โฆ
์ธ์ฆ ์๋ฒ์๊ฒ ์ธ์ฆ์ ๋ฐ๊ณ ๋ฆฌ์์ค ์ค๋์ ๋ฆฌ์์ค๋ฅผ ์ฌ์ฉํ๋ ์ฃผ์ฒด๋ฅผ ์๋ฏธํ๋ค. ์ง๊ธ ๋ง๋ค๊ณ ์๋ ์๋น์ค๊ฐ ์ด์ ํด๋น๋๋ค.
OAuth๋ฅผ ์ฌ์ฉํ๋ฉด ์ธ์ฆ ์๋ฒ์์ ๋ฐ๊ธ๋ฐ์ ํ ํฐ์ ์ฌ์ฉํ์ฌ ๋ฆฌ์์ค ์๋ฒ์ ๋ฆฌ์์ค ์ค๋์ ์ ๋ณด๋ฅผ ์์ฒญํ๊ณ ์๋ต๋ฐ์ ์ฌ์ฉํ ์ ์๋ค. ๊ทธ๋ฐ๋ฐ ํด๋ผ์ด์ธํธ๋ ์ด๋ป๊ฒ ๋ฆฌ์์ค ์ค๋์ ์ ๋ณด๋ฅผ ์ทจ๋ํ ์ ์์๊น?
๋ฆฌ์์ค ์ค๋ ์ ๋ณด๋ฅผ ์ทจ๋ํ ์ ์๋ ๋ฐฉ๋ฒ์ 4๊ฐ์ง๊ฐ ์๋ค.
โข
๋ฆฌ์์ค ์ค๋ ์ ๋ณด๋ฅผ ์ทจ๋ํ๋ 4๊ฐ์ง ๋ฐฉ๋ฒ
โฆ
๊ถํ ๋ถ์ฌ ์ฝ๋ ์น์ธ ํ์
(authorization code grant type)
โช
OAuth 2.0์์ ๊ฐ์ฅ ์ ์๋ ค์ง ์ธ์ฆ ๋ฐฉ๋ฒ์ด๋ค. ํด๋ผ์ด์ธํธ๊ฐ ๋ฆฌ์์ค์ ์ ๊ทผํ๋ ๋ฐ ์ฌ์ฉํ๋ฉฐ, ๊ถํ์ ์ ๊ทผํ ์ ์๋ ์ฝ๋์ ๋ฆฌ์์ค ์ค๋์ ๋ํ ์ก์ธ์ค ํ ํฐ์ ๋ฐ๊ธ๋ฐ๋ ๋ฐฉ์์ด๋ค.
โฆ
์์์ ์น์ธ ํ์
(implicit grant type)
โช
์๋ฒ๊ฐ ์๋ ์๋ฐ์คํฌ๋ฆฝํธ ์น ์ ํ๋ฆฌ์ผ์ด์
ํด๋ผ์ด์ธํธ์์ ์ฃผ๋ก ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ด๋ค.
ํด๋ผ์ด์ธํธ๊ฐ ์์ฒญ์ ๋ณด๋ด๋ฉด ๋ฆฌ์์ค ์ค๋์ ์ธ์ฆ ๊ณผ์ ์ด์ธ์๋ ๊ถํ ์ฝ๋ ๊ตํ ๋ฑ์ ๋ณ๋ค๋ฅธ ์ธ์ฆ ๊ณผ์ ์ ๊ฑฐ์น์ง ์๊ณ
์ก์ธ์ค ํ ํฐ์ ์ ๊ณต๋ฐ๋ ๋ฐฉ์์ด๋ค.
โฆ
๋ฆฌ์์ค ์์ ์ ์ํธ ์๊ฒฉ์ฆ๋ช
์น์ธ ํ์
(resource owner password credentials)
โช
ํด๋ผ์ด์ธํธ์ ํจ์ค์๋๋ฅผ ์ด์ฉํด์ ์ก์ธ์ค ํ ํฐ์ ๋ํ ์ฌ์ฉ์์ ์๊ฒฉ ์ฆ๋ช
์ ๊ตํํ๋ ๋ฐฉ์์ด๋ค.
โฆ
ํด๋ผ์ด์ธํธ ์๊ฒฉ์ฆ๋ช
์น์ธ ํ์
(client credentials grant)
โช
ํด๋ผ์ด์ธํธ๊ฐ ์ปจํ
์คํธ ์ธ๋ถ์์ ์ก์ธ์ค ํ ํฐ์ ์ป์ด ํน์ ๋ฆฌ์์ค์ ์ ๊ทผ์ ์์ฒญํ ๋ ์ฌ์ฉํ๋ ๋ฐฉ์์ด๋ค.
15์ผ์ฐจ
๋ณธ ํ๋ก์ ํธ๋ โ์คํ๋ง๋ถํธ 3 ๋ฐฑ์๋ ๊ฐ๋ฐ์ ๋๊ธฐโ ์์ ์ ์ฐธ๊ณ ํ์ฌ ์งํํ์์
JWTย ์๋น์ค ๊ตฌํ - ํ ์คํธ ์ฝ๋
โข
ํ
์คํธ ์ฝ๋ ์์ฑ
โฆ
generateToken() - ํ ํฐ์ ์์ฑํ๋ ๋ฉ์๋๋ฅผ ํ
์คํธํ๋ ๋ฉ์๋
@DisplayName("generateToken(): ์ ์ ์ ๋ณด์ ๋ง๋ฃ ๊ธฐ๊ฐ์ ์ ๋ฌํด ํ ํฐ์ ๋ง๋ค ์ ์๋ค.")
@Test
void generateToken() {
// given
User testUser = userRepository.save(User.builder()
.email("user@gmail.com")
.password("test")
.build());
// when
String token = tokenProvider.generateToken(testUser, Duration.ofDays(14));
// then
Long userId = Jwts.parser()
.setSigningKey(jwtProperties.getSecretkey())
.parseClaimsJws(token)
.getBody()
.get("id", Long.class);
assertThat(userId).isEqualTo(testUser.getId());
}
Java
๋ณต์ฌ
given | ํ ํฐ์ ์ ์ ์ ๋ณด๋ฅผ ์ถ๊ฐํ๊ธฐ ์ํ ํ
์คํธ ์ ์ ๋ฅผ ๋ง๋ ๋ค. |
when | ํ ํฐ ์ ๊ณต์์ generateToken() ๋ฉ์๋๋ฅผ ํธ์ถํด ํ ํฐ์ ๋ง๋ ๋ค. |
then | jjwt ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํด ํ ํฐ์ ๋ณตํธํํ๋ค. ํ ํฐ์ ๋ง๋ค ๋ ํด๋ ์์ผ๋ก ๋ฃ์ด๋ id๊ฐ์ด given์ ์์ ๋ง๋ ์ ์ ID์ ๋์ผํ์ง ํ์ธํ๋ค. |
โฆ
validToken_invalidToken()
// validToken() ๊ฒ์ฆ ํ
์คํธ
@DisplayName("validToken(): ๋ง๋ฃ๋ ํ ํฐ์ธ ๋์ ์ ํจ์ฑ ๊ฒ์ฆ์ ์คํจํ๋ค.")
@Test
void vaildToken_invalidToken() {
// given
String token = JwtFactory.builder()
.expiration(new Date(new Date().getTime() - Duration.ofDays(7).toMillis()))
.build()
.createToken(jwtProperties);
// when
boolean result = tokenProvider.vaildToken(token);
// then
assertThat(result).isFalse();
}
Java
๋ณต์ฌ
validToken_invalidToken() ๋ฉ์๋๋ ํ ํฐ์ด ์ ํจํ ํ ํฐ์ธ์ง ๊ฒ์ฆํ๋ ๋ฉ์๋์ธ validToken() ๋ฉ์๋๋ฅผ ํ
์คํธํ๋ ๋ฉ์๋์ด๋ค. ๊ฒ์ฆ ์คํจ๋ฅผ ํ์ธํ๋ validToken_invalidToken() ๋ฉ์๋์ ๊ฒ์ฆ ์ฑ๊ณต์ ํ์ธํ๋ validToken_validToken() ๋ฉ์๋๋ก ๊ตฌ์ฑํ์๋ค.
given | jjwt ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ฌ ํ ํฐ์ ์์ฑํ๋ค. ์ด๋ ๋ง๋ฃ ์๊ฐ์ 1970๋
1์ 1์ผ๋ถํฐ ํ์ฌ ์๊ฐ์ ๋ฐ๋ฆฌ์ด ๋จ์๋ก ์นํํ ๊ฐ(new Date().getTime())์ 1000์ ๋นผ, ์ด๋ฏธ ๋ง๋ฃ๋ ํ ํฐ์ผ๋ก ์์ฑํ๋ค. |
when | ํ ํฐ ์ ๊ณต์์ validToken() ๋ฉ์๋๋ฅผ ํธ์ถํด ์ ํจํ ํ ํฐ์ธ์ง ๊ฒ์ฆํ ๋ค ๊ฒฐ๊ณผ๊ฐ์ ๋ฐํ๋ฐ๋๋ค. |
then | ๋ฐํ๊ฐ์ด false(์ ํจํ ํ ํฐ์ด ์๋)์ธ ๊ฒ์ ํ์ธํ๋ค. |
โฆ
valid_validToken()
@DisplayName("validToken(): ์ ํจํ ํ ํฐ์ธ ๋์ ์ ํจ์ฑ ๊ฒ์ฆ์ ์ฑ๊ณตํ๋ค.")
@Test
void validToken_validToken() {
// given
String token = JwtFactory.withDefaultValues()
.createToken(jwtProperties);
// when
boolean result = tokenProvider.vaildToken(token);
// then
assertThat(result).isTrue();
}
Java
๋ณต์ฌ
given | jjwt ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ฌ ํ ํฐ์ ์์ฑํ๋ค. ๋ง๋ฃ ์๊ฐ์ ํ์ฌ ์๊ฐ์ผ๋ก๋ถํฐ 14์ผ ๋ค๋ก, ๋ง๋ฃ๋์ง ์์ ํ ํฐ์ผ๋ก ์์ฑํ๋ค. |
when | ํ ํฐ ์ ๊ณต์์ validToken() ๋ฉ์๋๋ฅผ ํธ์ถํด ์ ํจํ ํ ํฐ์ธ์ง ๊ฒ์ฆํ ๋ค ๊ฒฐ๊ณผ๊ฐ์ ๋ฐํ๋ฐ๋๋ค. |
then | ๋ฐํ๊ฐ์ด true(์ ํจํ ํ ํฐ์)์ธ ๊ฒ์ ํ์ธํ๋ค. |
โฆ
getAuthentication() - ํ ํฐ์ ์ ๋ฌ๋ฐ์ ์ธ์ฆ ์ ๋ณด๋ฅผ ๋ด์ ๊ฐ์ฒด Authentication์ ๋ฐํํ๋ ๋ฉ์๋์ธ getAuthentication()์ ํ
์คํธํ๋ค.
// getAuthentication() ๊ฒ์ฆ ํ
์คํธ
@DisplayName("getAuthentication(): ํ ํฐ ๊ธฐ๋ฐ์ผ๋ก ์ธ์ฆ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ฌ ์ ์๋ค.")
@Test
void getAuthentication() {
// given
String userEmail = "user@email.com";
String token = JwtFactory.builder()
.subject(userEmail)
.build()
.createToken(jwtProperties);
// when
Authentication authentication = tokenProvider.getAuthentication(token);
// then
assertThat(((UserDetails) authentication.getPrincipal()).getUsername()).isEqualTo(userEmail);
}
Java
๋ณต์ฌ
given | jjwt ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ฌ ํ ํฐ์ ์์ฑํ๋ค. ์ด๋ ํ ํฐ์ ์ ๋ชฉ์ธ subject๋ โuser@email.comโ๋ผ๋ ๊ฐ์ ์ฌ์ฉํ๋ค. |
when | ํ ํฐ ์ ๊ณต์์ getAuthentication() ๋ฉ์๋๋ฅผ ํธ์ถํด ์ธ์ฆ ๊ฐ์ฒด๋ฅผ ๋ฐํ๋ฐ๋๋ค. |
then | ๋ฐํ๋ฐ์ ์ธ์ฆ ๊ฐ์ฒด์ ์ ์ ์ด๋ฆ์ ๊ฐ์ ธ์ given์ ์์ ์ค์ ํ subject๊ฐ์ธ โuser@email.comโ๊ณผ ๊ฐ์์ง ํ์ธํ๋ค. |
โฆ
getUserId() ๋ฉ์๋๋ ํ ํฐ ๊ธฐ๋ฐ์ผ๋ก ์ ์ ID๋ฅผ ๊ฐ์ ธ์ค๋ ๋ฉ์๋๋ฅผ ํ
์คํธํ๋ ๋ฉ์๋์ด๋ค. ํ ํฐ์ ํ๋กํผํฐ์ฆ ํ์ผ์ ์ ์ฅํ ๋น๋ฐ๊ฐ์ผ๋ก ๋ณตํธํํ ๋ค ํด๋ ์์ ๊ฐ์ ธ์ค๋ private ๋ฉ์๋์ธ getClaims()๋ฅผ ํธ์ถํด์ ํด๋ ์ ์ ๋ณด๋ฅผ ๋ฐํ๋ฐ์ ํด๋ ์์์ id ํค๋ก ์ ์ฅ๋ ๊ฐ์ ๊ฐ์ ธ์ ๋ฐํํ๋ค.
// getUserId() ๊ฒ์ฆ ํ
์คํธ
@DisplayName("getUserId(): ํ ํฐ์ผ๋ก ์ ์ ID๋ฅผ ๊ฐ์ ธ์ฌ ์ ์๋ค.")
@Test
void getUserId() {
// given
Long userId = 1L;
String token = JwtFactory.builder()
.claims(Map.of("id", userId))
.build()
.createToken(jwtProperties);
// when
Long userIdByToken = tokenProvider.getUserId(token);
// then
assertThat(userIdByToken).isEqualTo(userId);
}
Java
๋ณต์ฌ
given | jjwt ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํด ํ ํฐ์ ์์ฑํ๋ค. ์ด๋ ํด๋ ์์ ์ถ๊ฐํ๋ค. ํค๋ โidโ, ๊ฐ์ 1์ด๋ผ๋ ์ ์ ID ์ด๋ค. |
when | ํ ํฐ ์ ๊ณต์์ getUserId() ๋ฉ์๋๋ฅผ ํธ์ถํด ์ ์ ID๋ฅผ ๋ฐํ๋ฐ๋๋ค. |
then | ๋ฐํ๋ฐ์ ์ ์ ID๊ฐ given ์ ์์ ์ค์ ํ ์ ์ ID๊ฐ์ธ 1๊ณผ ๊ฐ์์ง ํ์ธํ๋ค. |
โฆ
ํ
์คํธ ๊ฒฐ๊ณผ ํ์ธ

14์ผ์ฐจ
๋ณธ ํ๋ก์ ํธ๋ โ์คํ๋ง๋ถํธ 3 ๋ฐฑ์๋ ๊ฐ๋ฐ์ ๋๊ธฐโ ์์ ์ ์ฐธ๊ณ ํ์ฌ ์งํํ์์
JWTย ์๋น์ค ๊ตฌํ
โข
์์กด์ฑ ์ถ๊ฐ
โข
ํ ํฐ ์ ๊ณต์ ์ถ๊ฐ
โข
ํด๋น ๊ฐ๋ค์ ๋ณ์๋ก ์ ๊ทผํ๋ ๋ฐ ์ฌ์ฉํ JwtPropertiesย ์์ฑ
โข
ํ ํฐ์ ์์ฑํ๊ณ ์ฌ๋ฐ๋ฅธ ํ ํฐ์ธ์ง ์ ํจ์ฑ ๊ฒ์ฌ๋ฅผ ํ๊ธฐ ์ํด ํ ํฐ์์ ํ์ํ ์ ๋ณด ๊ฐ์ ธ์ค๋ ํด๋์ค ์์ฑ (TokenProvider.java)
13์ผ์ฐจ
๋ณธ ํ๋ก์ ํธ๋ โ์คํ๋ง๋ถํธ 3 ๋ฐฑ์๋ ๊ฐ๋ฐ์ ๋๊ธฐโ ์์ ์ ์ฐธ๊ณ ํ์ฌ ์งํํ์์
ํ์๊ฐ์ , ๋ก๊ทธ์ธ ๋ทฐ ์์ฑํ๊ธฐ
โข
๋ทฐ ์ปจํธ๋กค๋ฌ ๊ตฌํ
โข
๋ทฐ ์์ฑ - login.html, signup.html
๋ก๊ทธ์์ ๋ฉ์๋ ์์ฑ
โข
UserApiController ์์
12์ผ์ฐจ
๋ณธ ํ๋ก์ ํธ๋ โ์คํ๋ง๋ถํธ 3 ๋ฐฑ์๋ ๊ฐ๋ฐ์ ๋๊ธฐโ ์์ ์ ์ฐธ๊ณ ํ์ฌ ์งํํ์์
ํ์๊ฐ์ ๊ตฌํํ๊ธฐ
โข
์ฌ์ฉ์ ์ ๋ณด ๋ด๊ณ ์๋ ๊ฐ์ฒด ์์ฑ
โข
AddUserRequest ๊ฐ์ฒด๋ฅผ ์ธ์๋ก ๋ฐ๋ ํ์ ์ ๋ณด ์ถ๊ฐ ๋ฉ์๋ ์์ฑ - ์๋น์ค
โข
ํ์๊ฐ์
ํผ์์ ํ์ ๊ฐ์
์์ฒญ์ ๋ฐ์ผ๋ฉด ์๋น์ค ๋ฉ์๋ ์ฌ์ฉํด ์ฌ์ฉ์ ์ ์ฅ ํ ๋ก๊ทธ์ธ ํ์ด์ง๋ก ์ด๋ํ๋ signup ๋ฉ์๋ ์์ฑ
11์ผ์ฐจ
๋ณธ ํ๋ก์ ํธ๋ โ์คํ๋ง๋ถํธ 3 ๋ฐฑ์๋ ๊ฐ๋ฐ์ ๋๊ธฐโ ์์ ์ ์ฐธ๊ณ ํ์ฌ ์งํํ์์
์ํ๋ฆฌํฐ ์ค์ ํ๊ธฐ
โข
requestMathcers(): ํน์ ์์ฒญ๊ณผ ์ผ์นํ๋ url์ ๋ํ ์ก์ธ์ค๋ฅผ ์ค์ ํ๋ค.
โข
permitAll(): ๋๊ตฌ๋ ์ ๊ทผ์ด ๊ฐ๋ฅํ๊ฒ ์ค์ ํ๋ค.
โข
anyRequest(): ์์์ ์ค์ ํ url ์ด์ธ์ ์์ฒญ์ ๋ํด ์ค์ ํ๋ค.
โข
loginPage(): ๋ก๊ทธ์ธ ํ์ด์ง ๊ฒฝ๋ก ์ค์ ํ๋ค.
โข
defaultSuccessUrl(): ๋ก๊ทธ์ธ์ด ์๋ฃ๋์์ ๋ ์ด๋ํ ๊ฒฝ๋ก๋ฅผ ์ค์ ํ๋ค.
โข
logoutSuccessURl(): ๋ก๊ทธ์์์ด ์๋ฃ๋์์ ๋ ์ด๋ํ ๊ฒฝ๋ก๋ฅผ ์ค์ ํ๋ค.
โข
invalidateHttpSession(): ๋ก๊ทธ์์ ์ดํ์ ์ธ์
์ ์ ์ฒด ์ญ์ ํ ์ง ์ฌ๋ถ๋ฅผ ๊ฒฐ์ ํ๋ค.
โข
userDetailService: ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ฌ ์๋น์ค๋ฅผ ์ค์ ํ๋ค. ์ด๋ ์ค์ ํ๋ ์๋น์ค ํด๋์ค๋ ๋ฐ๋์ UserDetailsService๋ฅผ ์์๋ฐ์ ํด๋์ค์ฌ์ผ ํ๋ค.
โข
passwrodEncoder(): ๋น๋ฐ๋ฒํธ๋ฅผ ์ํธํํ๊ธฐ ์ํ ์ธ์ฝ๋๋ฅผ ์ค์ ํ๋ค.
10์ผ์ฐจ
๋ณธ ํ๋ก์ ํธ๋ โ์คํ๋ง๋ถํธ 3 ๋ฐฑ์๋ ๊ฐ๋ฐ์ ๋๊ธฐโ ์์ ์ ์ฐธ๊ณ ํ์ฌ ์งํํ์์
ํ์ ๋๋ฉ์ธ ๋ง๋ค๊ธฐ
โข
์์กด์ฑ ์ถ๊ฐํ๊ธฐ
โข
ํ์ ์ํฐํฐ ๋ง๋ค๊ธฐ
โข
domain ํจํค์ง์ UserDetail ํด๋์ค๋ฅผ ์์ํ๋ User ํด๋์ค ์์ฑ
โข
UserRepository ์์ฑ
9์ผ์ฐจ
๋ณธ ํ๋ก์ ํธ๋ โ์คํ๋ง๋ถํธ 3 ๋ฐฑ์๋ ๊ฐ๋ฐ์ ๋๊ธฐโ ์์ ์ ์ฐธ๊ณ ํ์ฌ ์งํํ์์
์์ฑ ๊ธฐ๋ฅ ๋ง๋ฌด๋ฆฌ
โข
article.js ์ ์ฝ๋ ์์ฑ
โข
article.js ํ์ผ์ ์ด์ด [๋ฑ๋ก] ๋ฒํผ์ ๋๋ฅด๋ฉด ์
๋ ฅ ์นธ์ ์๋ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ ๊ฒ์๊ธ ์์ฑ API์ ๊ธ ์์ฑ ๊ด๋ จ ์์ฒญ์ ๋ณด๋ด์ค๋ค.
โข
id๊ฐ create-btn์ธ ์๋ฆฌ๋จผํธ๋ฅผ ์ฐพ์ ๊ทธ ์๋ฆฌ๋จผํธ์์ ํด๋ฆญ ์ด๋ฒคํธ ๋ฐ์ ์ id๊ฐ title, content์ธ ์๋ฆฌ๋จผํธ์ ๊ฐ์ ๊ฐ์ ธ์ fetch() ๋ฉ์๋๋ฅผ ํตํด ์์ฑ API๋ก /api/articles/ POST ์์ฒญ์ ๋ณด๋ธ๋ค.
โข
articleList.html ํ์ผ ์์
โข
๊ฒฐ๊ณผ ํ์ธ
8์ผ์ฐจ
๋ณธ ํ๋ก์ ํธ๋ โ์คํ๋ง๋ถํธ 3 ๋ฐฑ์๋ ๊ฐ๋ฐ์ ๋๊ธฐโ ์์ ์ ์ฐธ๊ณ ํ์ฌ ์งํํ์์
ํธ๋ฌ๋ธ์ํ
โข
์คํ๋ง ๋ถํธ 3.2 ๋ฒ์ ๋งค๊ฐ๋ณ์ ์ด๋ฆ ์ธ์ ๋ฌธ์
โฆ
์คํ๋ง ๋ถํธ 3.2๋ถํฐ ๋งค๊ฐ๋ณ์ ์ด๋ฆ์ ์ธ์ํ์ง ๋ชปํ๋ ๋ฌธ์ ๊ฐ ์๋๋ฐ ์๋ฐ ์ปดํ์ผ๋ฌ์ -parameter ์ต์
์ ๋ฃ์ด์ฃผ์ด์ผ ์ ๋
ธํ
์ด์
์ ์ด๋ฆ์ ์๋ตํ ์ ์๋ค.
โฆ
ํด๋น ์ผ์ด์ค ๊ฐ์ ๊ฒฝ์ฐ ๋น๋ ์ Gradle์ด ์๋ IntelliJ IDEAย ๋ก ์ค์ ๋์ด ์์ด์ ๋ฐ์ํ ๋ฌธ์ ์๋ค.
โฆ
Gradle์ ์ฌ์ฉํด์ ๋น๋ํ๊ณ ์คํํ๋ค. ์ด๋ ๊ฒ ํ๋ฉด parameter ์ถ๊ฐํ ํ์ ์๋ค.

โฆ
๋ง์ฝ์ IntelliJ IDEA ๋ก ์ ์ง๋ฅผ ํ๊ณ ์ฌ์ฉํด์ผ ํ๋ค๋ฉด ์ ๋ํ
์ด์
์์ -parameter ์ต์
์ ์ถ๊ฐํด์ฃผ์ด์ผ ํ๋ค.
โฆ
์คํ๋ง ๋ถํธ 3.2 ์ ๊น์ง๋ ๋ฐ์ดํธ์ฝ๋๋ฅผ ํ์ฑํด์ ๋งค๊ฐ๋ณ์ ์ด๋ฆ์ ์ถ๋ก ํ๋ ค๊ณ ์๋ํ์ผ๋ ์คํ๋ง ๋ถํธ 3.2๋ถํฐ๋ ์ด๋ฐ ์๋๋ฅผ ํ์ง ์๋๋ค.
๊ทธ๋์ ์๋ฌ๊ฐ ๋ฐ์ํ ๊ฒ์ด๋ค.
โข
์๋ฌ ํด๊ฒฐ ํ ์ ์์ ์ผ๋ก ๊ธ ์์ธ ํ๋ฉด์ด ์ ๋์ค๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.

7์ผ์ฐจ
๋ณธ ํ๋ก์ ํธ๋ โ์คํ๋ง๋ถํธ 3 ๋ฐฑ์๋ ๊ฐ๋ฐ์ ๋๊ธฐโ ์์ ์ ์ฐธ๊ณ ํ์ฌ ์งํํ์์
๋ธ๋ก๊ทธ ๊ธ ๋ชฉ๋ก ๋ทฐ ๊ตฌํ
โข
์์ฒญ์ ๋ฐ์ ์ฌ์ฉ์์๊ฒ ๋ทฐ๋ฅผ ๋ณด์ฌ์ฃผ๋ ค๋ฉด ๋ทฐ ์ปจํธ๋กค๋ฌ๊ฐ ํ์ํจ
โข
๋ทฐ ์ปจํธ๋กค๋ฌ ๋ฉ์๋๋ ๋ทฐ์ ์ด๋ฆ์ ๋ฐํํ๊ณ , ๋ชจ๋ธ ๊ฐ์ฒด์ ๊ฐ์ ๋ด์
โข
๋ทฐ์ ์ ๋ฌํ๊ธฐ ์ํ ๊ฐ์ฒด ์์ฑ
โข
/article GETย ์์ฒญ์ ์ฒ๋ฆฌํ ์ฝ๋ ์์ฑ - ๋ธ๋ก๊ทธ ๊ธ ์ ์ฒด ๋ฆฌ์คํธ๋ฅผ ๋ด์ ๋ทฐ๋ฅผ ๋ฐํ
โฆ
addAttribute() ๋ฉ์๋๋ฅผ ์ฌ์ฉํด ๋ชจ๋ธ์ ๊ฐ์ ์ ์ฅ
โฆ
โarticlesโ ํค์ ๋ธ๋ก๊ทธ ๊ธ๋ค์, ์ฆ, ๊ธ ๋ฆฌ์คํธ๋ฅผ ์ ์ฅ
โข
HTML ๋ทฐ ๋ง๋ค๊ธฐ
โฆ
th:each๋ก โarticlesโ ํค์ ๋ด๊ธด ๋ฐ์ดํฐ ๊ฐ์๋งํผ ๋ฐ๋ณต
โฆ
th:text ๋ ๋ฐ๋ณต ๋์ ๊ฐ์ฒด์ id, โtextโ ๋ฅผ ์ถ๋ ฅ
6์ผ์ฐจ
๋ณธ ํ๋ก์ ํธ๋ โ์คํ๋ง๋ถํธ 3 ๋ฐฑ์๋ ๊ฐ๋ฐ์ ๋๊ธฐโ ์์ ์ ์ฐธ๊ณ ํ์ฌ ์งํํ์์
ํ์๋ฆฌํ
โข
๋ทฐ ์์ฑ - example.html
โข
์ถ๋ ฅ ๊ฒฐ๊ณผ

5์ผ์ฐจ
๋ณธ ํ๋ก์ ํธ๋ โ์คํ๋ง๋ถํธ 3 ๋ฐฑ์๋ ๊ฐ๋ฐ์ ๋๊ธฐโ ์์ ์ ์ฐธ๊ณ ํ์ฌ ์งํํ์์
ํ์๋ฆฌํ
โข
ํ์๋ฆฌํ๋ ํ
ํ๋ฆฟ ์์ง์ด๋ค.
โฆ
ํ
ํ๋ฆฟ ์์ง: ์คํ๋ง ์๋ฒ์์ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์ ์ฐ๋ฆฌ๊ฐ ๋ณด๋ ์น ํ์ด์ง, ์ฆ HTML ์์ ๊ทธ ๋ฐ์ดํฐ๋ฅผ ๋ฃ์ด ๋ณด์ฌ์ฃผ๋ ๋๊ตฌ์ด๋ค.
โข
๋ฌธ๋ฒ
ํํ์ | ์ค๋ช
|
${โฆ} | ๋ณ์์ ๊ฐ ํํ์ |
#{โฆ} | ์์ฑ ํ์ผ ๊ฐ ํํ์ |
@{โฆ} | URL ํํ์ |
*{โฆ} | ์ ํํ ๋ณ์์ ํํ์. th:object์์ ์ ํํ ๊ฐ์ฒด์ ์ ๊ทผ |
th:text | ํ
์คํธ๋ฅผ ํํํ ๋ ์ฌ์ฉ - th:text=${person.name} |
th:each | ์ปฌ๋ ์
์ ๋ฐ๋ณตํ ๋ ์ฌ์ฉ - th:each=โperson:${persons}โ |
th:if | ์กฐ๊ฑด์ด true์ธ ๋๋ง ํ์ - th:if=โ${person.age} โฅ 20โ |
th:unless | ์กฐ๊ฑด์ด false์ธ ๋๋ง ํ์ - th:unless=โ${person.age}โฅ20โ |
th:href | ์ด๋ ๊ฒฝ๋ก - th:href=โ@{/person(id=${person.id})}โ |
th:with | ๋ณ์๊ฐ์ผ๋ก ์ง์ - th:with=โname = ${person.name}โ |
th:object | ์ ํํ ๊ฐ์ฒด๋ก ์ง์ - th:object=โ${person}โ |
โข
ํ์๋ฆฌํ ์์กด์ฑ ์ถ๊ฐ
โข
ํ์๋ฆฌํ ๋ฌธ๋ฒ ์ตํ๊ธฐ์ฉ ์ปจํธ๋กค๋ฌ ์์ฑ
โฆ
๋ชจ๋ธ(Model) ๊ฐ์ฒด๋ ๋ทฐ, ์ฆ, HTML ์ชฝ์ผ๋ก ๊ฐ์ ๋๊ฒจ์ฃผ๋ ๊ฐ์ฒด์ด๋ค.
โฆ
๋ชจ๋ธ ๊ฐ์ฒด๋ ๋ฐ๋ก ์์ฑํ ํ์ ์์ด ์ฝ๋์ฒ๋ผ ์ธ์๋ก ์ ์ธํ๊ธฐ๋ง ํ๋ฉด ์คํ๋ง์ด ์์์ ๋ง๋ค์ด์ฃผ๋ฏ๋ก ํธ๋ฆฌํ๊ฒ ์ฌ์ฉํ ์ ์๋ค.
4์ผ์ฐจ
๋ณธ ํ๋ก์ ํธ๋ โ์คํ๋ง๋ถํธ 3 ๋ฐฑ์๋ ๊ฐ๋ฐ์ ๋๊ธฐโ ์์ ์ ์ฐธ๊ณ ํ์ฌ ์งํํ์์
๋ธ๋ก๊ทธ ๊ธ ์ญ์ API ๊ตฌํ
โข
BlogService.java
โข
BlogApiController.java
โข
์ญ์ ๊ฒฐ๊ณผ ํ์ธ
โฆ
postman ํ
์คํธ (์ผ์ชฝ - DELETE ์์ฒญ ๋ณด๋, ์ค๋ฅธ์ชฝ - DELETE ์์ฒญ ๋ณด๋ธ ํ)


โฆ
๊ฒฐ๊ณผ ํ์ธ (์ผ์ชฝ - ๋ณ๊ฒฝ ์ , ์ค๋ฅธ์ชฝ - ๋ณ๊ฒฝ ํ)


โข
ํ
์คํธ ์ฝ๋ ์์ฑ - BlogApiControllerTest.java
@DisplayName("deleteArticle: ๋ธ๋ก๊ทธ ๊ธ ์ญ์ ์ ์ฑ๊ณตํ๋ค.")
@Test
public void deleteArticle() throws Exception {
// given
final String url = "/api/articles/{id}";
final String title = "title";
final String content = "content";
Article savedArticle = blogRepository.save(Article.builder()
.title(title)
.content(content)
.build());
// when
mockMvc.perform(delete(url, savedArticle.getId()))
.andExpect(status().isOk());
// then
List<Article> articles = blogRepository.findAll();
assertThat(articles).isEmpty();
Java
๋ณต์ฌ
๋ธ๋ก๊ทธ ๊ธ ์์ API ๊ตฌํ
3์ผ์ฐจ
๋ณธ ํ๋ก์ ํธ๋ โ์คํ๋ง๋ถํธ 3 ๋ฐฑ์๋ ๊ฐ๋ฐ์ ๋๊ธฐโ ์์ ์ ์ฐธ๊ณ ํ์ฌ ์งํํ์์
๋ธ๋ก๊ทธ์ ๋ชจ๋ ๊ธ ์กฐํํ๋ API ๊ตฌํ
โข
BlogService.java
์๋ต์ ์ํ DTO ์์ฑ
โข
ArticleResponse.java
์ ์ฒด ๊ธ์ ์กฐํํ ๋ค ๋ฐํ
2์ผ์ฐจ
๋ณธ ํ๋ก์ ํธ๋ โ์คํ๋ง๋ถํธ 3 ๋ฐฑ์๋ ๊ฐ๋ฐ์ ๋๊ธฐโ ์์ ์ ์ฐธ๊ณ ํ์ฌ ์งํํ์์
์ํฐํฐ ๊ตฌ์ฑ
๋ฆฌํฌ์งํ ๋ฆฌ ๋ง๋ค๊ธฐ
API ๊ตฌํ
โข
DTO (Data Transfer Object)
1์ผ์ฐจ

