์คํ๋ง ๋ถํธ์ ์คํ๋ง ์ํ๋ฆฌํฐ ํตํฉ: JWT์ OAuth2๋ก ์ธ์ฆ ๋ฐ ์ธ๊ฐ ๊ตฌํํ๊ธฐ
์คํ๋ง ๋ถํธ(Spring Boot) ์ ์คํ๋ง ์ํ๋ฆฌํฐ(Spring Security) ๋ฅผ ์ฌ์ฉํ๋ฉด ์ ํ๋ฆฌ์ผ์ด์ ์ ์ธ์ฆ(Authentication) ๊ณผ ์ธ๊ฐ(Authorization) ๋ฅผ ํจ๊ณผ์ ์ผ๋ก ๊ด๋ฆฌํ ์ ์์ต๋๋ค. ์ด๋ฒ ํฌ์คํ ์์๋ ์ธ์ฆ๊ณผ ์ธ๊ฐ ๊ฐ๋ ์ ์ค๋ช ํ๊ณ , JWT(Json Web Token)๋ฅผ ํ์ฉํ ๋ก๊ทธ์ธ ์ฒ๋ฆฌ ์ OAuth 2.0์ ์ด์ฉํ ์์ ๋ก๊ทธ์ธ ๊ตฌํ ๋ฐฉ๋ฒ์ ์์ ์ ํจ๊ป ์์๋ด ๋๋ค.
๋ชฉ์ฐจ
- ์คํ๋ง ์ํ๋ฆฌํฐ์ ์ธ์ฆ๊ณผ ์ธ๊ฐ ๊ฐ๋
- JWT๋ฅผ ํ์ฉํ ๋ก๊ทธ์ธ ์ฒ๋ฆฌ
- OAuth 2.0 ๋ก๊ทธ์ธ ๊ตฌํํ๊ธฐ
- ์ธ์ฆ๊ณผ ์ธ๊ฐ์ ์ต์ ํธ๋ ๋์ ์ค์์ฑ
- JWT์ OAuth 2.0 ์์ ์ฝ๋ ๋ฐ ์คํ ๋ฐฉ๋ฒ
1. ์คํ๋ง ์ํ๋ฆฌํฐ์ ์ธ์ฆ๊ณผ ์ธ๊ฐ ๊ฐ๋
์คํ๋ง ์ํ๋ฆฌํฐ ๋ ์คํ๋ง ํ๋ ์์ํฌ์ ํตํฉ๋ ๋ณด์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ก, ์ธ์ฆ ๊ณผ ์ธ๊ฐ ๋ฅผ ์ฒ๋ฆฌํ๋ ๋ฐ ์ต์ ํ๋ ์๋ฃจ์ ์ ๋๋ค.
- ์ธ์ฆ(Authentication) : ์ฌ์ฉ์๊ฐ ๋๊ตฌ์ธ์ง ํ์ธํ๋ ์ ์ฐจ์ ๋๋ค. (์: ๋ก๊ทธ์ธ)
- ์ธ๊ฐ(Authorization) : ์ฌ์ฉ์๊ฐ ์ด๋ค ๋ฆฌ์์ค์ ์ ๊ทผํ ์ ์๋์ง๋ฅผ ๊ฒฐ์ ํฉ๋๋ค. (์: ๊ด๋ฆฌ์ ๊ถํ๋ง ํน์ ํ์ด์ง ์ ๊ทผ)
๊ตฌ๋ถ | ์ค๋ช | ์์ |
---|---|---|
์ธ์ฆ | ์ฌ์ฉ์๊ฐ ์ฌ๋ฐ๋ฅธ ์๊ฒฉ ์ฆ๋ช ์ ์ ๊ณตํ๋์ง ํ์ธ | ID์ ๋น๋ฐ๋ฒํธ๋ก ๋ก๊ทธ์ธ |
์ธ๊ฐ | ์ฌ์ฉ์๊ฐ ๋ฆฌ์์ค์ ์ ๊ทผํ ์ ์๋ ๊ถํ์ด ์๋์ง ํ์ธ | ๊ด๋ฆฌ์๋ง ์ ๊ทผ ๊ฐ๋ฅํ ํ์ด์ง |
2. JWT๋ฅผ ํ์ฉํ ๋ก๊ทธ์ธ ์ฒ๋ฆฌ
JWT๋ ๋ฌด์์ธ๊ฐ?
JWT(Json Web Token) ๋ ์ฌ์ฉ์ ์ธ์ฆ ์ ๋ณด๋ฅผ ์ํธํ ํ ํ ํฐ์ผ๋ก, ๋ก๊ทธ์ธ ํ ํด๋ผ์ด์ธํธ์๊ฒ ํ ํฐ์ ๋ฐ๊ธํ๊ณ ์ดํ ์์ฒญ๋ง๋ค ์ด ํ ํฐ์ ์ฌ์ฉํด ์ธ์ฆํฉ๋๋ค.
JWT ์ธ์ฆ ํ๋ฆ
- ์ฌ์ฉ์๊ฐ ID์ ๋น๋ฐ๋ฒํธ๋ก ๋ก๊ทธ์ธ ์์ฒญ
- ์๋ฒ์์ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ํ์ธ ํ JWT ๋ฐ๊ธ
- ํด๋ผ์ด์ธํธ๋ JWT๋ฅผ ์ ์ฅํ๊ณ ์ดํ ์์ฒญ์ ํค๋์ ํฌํจ ํด ์๋ฒ๋ก ์ ์ก
- ์๋ฒ๋ JWT๋ฅผ ๊ฒ์ฆํด ์์ฒญ ์ฒ๋ฆฌ
JWT ๋ฐ๊ธ ๋ฐ ์ธ์ฆ ์์ ์ฝ๋
pom.xml ์์กด์ฑ ์ถ๊ฐ
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.2</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.2</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.2</version>
</dependency>
JwtTokenProvider.java (JWT ํ ํฐ ์์ฑ ๋ฐ ๊ฒ์ฆ)
package com.example.demo.security;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.stereotype.Component;
import java.util.Date;
@Component
public class JwtTokenProvider {
private final String SECRET_KEY = "mySecretKey";
private final long EXPIRATION_TIME = 86400000; // 24์๊ฐ
public String generateToken(String username) {
return Jwts.builder()
.setSubject(username)
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
.signWith(SignatureAlgorithm.HS512, SECRET_KEY)
.compact();
}
public String validateAndGetUsername(String token) {
Claims claims = Jwts.parser()
.setSigningKey(SECRET_KEY)
.parseClaimsJws(token)
.getBody();
return claims.getSubject();
}
}
SecurityConfig.java (์คํ๋ง ์ํ๋ฆฌํฐ ์ค์ )
package com.example.demo.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/api/login").permitAll()
.anyRequest().authenticated();
}
}
JWT ๋ฐ๊ธ ๋ฐ ์ธ์ฆ ํ ์คํธ
- POST /api/login : ๋ก๊ทธ์ธ ํ JWT ๋ฐ๊ธ
- ์ดํ ์์ฒญ์ Authorization ํค๋ ๋ก
Bearer {token}
์ ํฌํจํด ์ธ์ฆ ์ฒ๋ฆฌ
3. OAuth 2.0 ๋ก๊ทธ์ธ ๊ตฌํํ๊ธฐ
OAuth 2.0์ด๋?
OAuth 2.0 ์ ๊ตฌ๊ธ, ํ์ด์ค๋ถ, ์นด์นด์ค ๋ฑ ์์ ๋ก๊ทธ์ธ ์ ๊ตฌํํ ๋ ์ฌ์ฉ๋๋ ํ๋กํ ์ฝ์ ๋๋ค. ์ฌ์ฉ์๊ฐ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ง์ ๋ก๊ทธ์ธํ์ง ์๊ณ , ์์ ๊ณ์ ์ผ๋ก ์ธ์ฆ ํ ์ ์๋๋ก ๋์์ค๋๋ค.
OAuth 2.0 ๋ก๊ทธ์ธ ํ๋ฆ
- ์ฌ์ฉ์๊ฐ ๊ตฌ๊ธ ๋ก๊ทธ์ธ ๋ฒํผ ํด๋ฆญ
- ๊ตฌ๊ธ์์ ์ธ์ฆ ํ ์ก์ธ์ค ํ ํฐ ๋ฐ๊ธ
- ์ ํ๋ฆฌ์ผ์ด์ ์ด ํ ํฐ์ ๋ฐ์ ์ฌ์ฉ์๋ฅผ ์๋ณ
OAuth 2.0 ์ค์ ์์
pom.xml ์์กด์ฑ ์ถ๊ฐ
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
application.yml ์ค์
spring:
security:
oauth2:
client:
registration:
google:
client-id: YOUR_GOOGLE_CLIENT_ID
client-secret: YOUR_GOOGLE_CLIENT_SECRET
redirect-uri: "{baseUrl}/login/oauth2/code/google"
scope: email, profile
client-authentication-method: basic
authorization-grant-type: authorization_code
provider:
google:
authorization-uri: https://accounts.google.com/o/oauth2/auth
token-uri: https://oauth2.googleapis.com/token
user-info-uri: https://www.googleapis.com/oauth2/v3/userinfo
SecurityConfig.java (OAuth 2.0 ์ค์ )
@Override
protected void configure(HttpSecurity http) throws Exception {
http.oauth2Login()
.loginPage("/login")
.defaultSuccessUrl("/home", true);
}
์คํ ๊ฒฐ๊ณผ
- /login ํ์ด์ง์์ ๊ตฌ๊ธ ๋ก๊ทธ์ธ ๋ฒํผ์ ํด๋ฆญํฉ๋๋ค.
- ๊ตฌ๊ธ ๊ณ์ ์ผ๋ก ๋ก๊ทธ์ธ ํ /home ํ์ด์ง๋ก ๋ฆฌ๋ค์ด๋ ํธ๋ฉ๋๋ค.
4. ์ธ์ฆ๊ณผ ์ธ๊ฐ์ ์ต์ ํธ๋ ๋์ ์ค์์ฑ
- JWT ๋ ๋ฌด์ํ(stateless) ์๋ฒ ์ ์ ๋ง์ ๋ง์ดํฌ๋ก์๋น์ค ์ํคํ ์ฒ ์์ ๋ง์ด ์ฌ์ฉ๋ฉ๋๋ค.
- OAuth 2.0 ์ ์์ ๋ก๊ทธ์ธ ์ ์ ๊ณตํ๋ฉฐ, ์ฌ์ฉ์ ๊ฒฝํ์ ๊ฐ์ ํ๊ณ ๋ณด์์ ๊ฐํํฉ๋๋ค.
- 2024๋ ๊ธฐ์ค, ํด๋ผ์ฐ๋ ํ๊ฒฝ ์์๋ JWT์ OAuth 2.0์ ํ์ฉํ ์ธ์ฆ ๋ฐ ์ธ๊ฐ๊ฐ ํ์์ ์ธ ๊ธฐ์ ๋ก ์๋ฆฌ ์ก๊ณ ์์ต๋๋ค.
๊ด๋ จ ๋งํฌ
Spring Security ๊ณต์ ๋ฌธ์๐
Spring Boot์ JWT ํํ ๋ฆฌ์ผ๐
Spring Boot ๊ณต์ ์ฌ์ดํธ๐
FAQ
1. JWT๋ ์ธ์ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข๋์?
- JWT๋ ๋ฌด์ํ(stateless) ์ธ์ฆ ์ด ํ์ํ RESTful API์์ ์ ์ฉํฉ๋๋ค.
2. OAuth 2.0๊ณผ JWT์ ์ฐจ์ด์ ์ ๋ฌด์์ธ๊ฐ์?
- OAuth 2.0์ ์์ ๋ก๊ทธ์ธ ์ ์ฌ์ฉ๋๋ฉฐ, JWT๋ ์ฃผ๋ก ํ ํฐ ๊ธฐ๋ฐ ์ธ์ฆ ์ ์ฌ์ฉ๋ฉ๋๋ค.
3. JWT ํ ํฐ์ ์์ ํ๊ฐ์?
- JWT๋ ์๋ช ๋ ํ ํฐ ์ผ๋ก ์๋ณ์กฐ๊ฐ ์ด๋ ต์ง๋ง, ๋ง๋ฃ ์๊ฐ ์ค์ ๊ณผ HTTPS ์ฌ์ฉ์ด ํ์ํฉ๋๋ค.
4. OAuth 2.0 ๊ตฌํ ์ ํด๋ผ์ด์ธํธ ID์ ๋น๋ฐ ํค๋ ์ด๋์ ์ป๋์?
- ์์ ์๋น์ค(์: ๊ตฌ๊ธ, ํ์ด์ค๋ถ) ๊ฐ๋ฐ์ ์ฝ์์์ ์์ฑํ ์ ์์ต๋๋ค.
5. JWT ํ ํฐ์ด ๋ง๋ฃ๋๋ฉด ์ด๋ป๊ฒ ํด์ผ ํ๋์?
- ๋ฆฌํ๋ ์ ํ ํฐ(refresh token) ์ ์ฌ์ฉํด ์๋ก์ด JWT๋ฅผ ๋ฐ๊ธ๋ฐ๋ ๋ฐฉ๋ฒ์ ์ฌ์ฉํฉ๋๋ค.
๋ง๋ฌด๋ฆฌ
์ด๋ฒ ํฌ์คํ ์์๋ ์คํ๋ง ๋ถํธ์ ์คํ๋ง ์ํ๋ฆฌํฐ ๋ฅผ ์ฌ์ฉํด JWT ๊ธฐ๋ฐ ์ธ์ฆ ๊ณผ OAuth 2.0 ์์ ๋ก๊ทธ์ธ ์ ๊ตฌํํ๋ ๋ฐฉ๋ฒ์ ์์๋ณด์์ต๋๋ค. JWT ๋ ๋ฌด์ํ ์ธ์ฆ ์ ์ ํฉํ์ฌ REST API์ ๋ง์ดํฌ๋ก์๋น์ค ํ๊ฒฝ์์ ๋ง์ด ์ฌ์ฉ๋ฉ๋๋ค. ๋ํ OAuth 2.0 ์ ์ฌ์ฉํ๋ฉด ๊ตฌ๊ธ, ํ์ด์ค๋ถ, ์นด์นด์ค ์ ๊ฐ์ ์์ ๊ณ์ ์ ํตํด ์ฌ์ฉ์ ์ธ์ฆ์ ๊ฐํธํ๊ฒ ์ฒ๋ฆฌํ ์ ์์ด ์ฌ์ฉ์ ๊ฒฝํ(UX)์ ํฌ๊ฒ ํฅ์์ํฌ ์ ์์ต๋๋ค.
์คํ๋ง ์ํ๋ฆฌํฐ ๋ ๋ค์ํ ์ธ์ฆ ๋ฐ ์ธ๊ฐ ๋ฐฉ๋ฒ์ ์ง์ํ๋ฉฐ, ์ ํ๋ฆฌ์ผ์ด์ ์ ์ ์ฐํ ๋ณด์ ์ค์ ์ ์ ๊ณตํฉ๋๋ค. ์ด๋ฒ ํฌ์คํ ์ ํตํด ์ฌ๋ฌ๋ถ์ ์ ํ๋ฆฌ์ผ์ด์ ์ ์์ ํ ๋ณด์ ๊ธฐ๋ฅ ์ ์ถ๊ฐํด ๋ณด์ธ์.
๋๊ธ