Security docs :
Spring Security
Spring Security is a powerful and highly customizable authentication and access-control framework. It is the de-facto standard for securing Spring-based applications. Spring Security is a framework that focuses on providing both authentication and authoriz
spring.io
๐บ ์ด๊ฑฐ ์ ? ํ๋ก์ ํธ ์งํ ์ค ํน์ API๋ฅผ ์ธ๋ถ์์ ์ธ ์ ์๋๋ก ์ธ์ฆ๊ณผ์ ์ ์ ๊ฑฐํด๋ฌ๋ผ๋ ์์ฒญ์ด ์์๊ณ , ์ ๊ฑฐ ํ ํ๋ก์ ํธ๋ฅผ ์คํ ์ด์ง ์๋ฒ์์ ๊ธฐ๋
-> API๋ ์์ ๋กญ๊ฒ ์ธ ์ ์์์ผ๋, ๊ด๋ จ๋ ๋ด๋ถ ๋ฉ์๋์์ ์ธ์ฆ์ด ์๋ ๊ฒฝ์ฐ ํน์ ๊ธฐ๋ฅ์ ์ฌ์ฉํ์ง ๋ชปํ๋ ์ํฉ์ด ๋ฐ์.
Security ์ ์ธ์ฆ์ ๋ํด ์ ๋ฆฌ ํ๊ณ ๋์ด๊ฐ๊ธฐ๋ก ํจ.
์์ ํ ํ๋ก์ ํธ ๋ฒ์
Spring-boot :
- Maven: org.springframework.security.oauth:spring-security-oauth2:2.3.4.RELEASE
- Maven: org.springframework.security:spring-security-config:5.5.1
- Maven: org.springframework.security:spring-security-core:5.5.1
- Maven: org.springframework.security:spring-security-crypto:5.5.1
- Maven: org.springframework.security:spring-security-web:5.5.1
JAVA : 1.8
Security & Oauth :
- Maven: org.springframework.security.oauth:spring-security-oauth2:2.3.4.RELEASE
- -> SPRING SECURITY 5.0๋ถํฐ 2.0๋ ๋ฒ์ ์ฌ์ฉ ๊ฐ๋ฅ.
- Maven: org.springframework.security:spring-security-config:5.5.1
- Maven: org.springframework.security:spring-security-core:5.5.1
- Maven: org.springframework.security:spring-security-crypto:5.5.1
- Maven: org.springframework.security:spring-security-web:5.5.1

Spring Security์ ์ ๊ณต ๊ธฐ๋ฅ
- Servlet API ํตํฉ
- Spring Web MVC์์ ์ ํ์ ํตํฉ
- ์ธ์ฆ ๊ถํ ๋ถ์ฌ๋ฅผ ํฌ๊ด์ ๋ก ํ์ฅํ๋ฉฐ ์ง์
- ์ธ์ ๊ณ ์ , clickjacking, ์ฌ์ดํธ๊ฐ ์์ฒญ ์์กฐ(CSRF) ๋ฐฉ์ง
์น ๊ธฐ๋ฐ ์ธ์ฆ ๋ฐ ์ธ๊ฐ๋ฅผ ํธํ๊ฒ ๊ตฌํํ๋๋ก ํจ.
๐ค stateless ํ HTTP์์์ ์ธ์ฆ ์ธ๊ฐ๊ฐ ์๋ค๋ฉด ๋น๋ฐ๋ฒํธ์ ์์ด๋๋ฅผ ๊ณ์ ์ ๋ ฅํด์ผ ํ๋ ๋ถ์์ฌ๊ฐ ์๊ธธ ์ ๋์๋ค.
์ธ์ฆ? : ์ฌ์ฉ์์ ์ ์ ํ์ธ
์ธ๊ฐ? : ์ฌ์ฉ์๊ฐ ํน์ ๋ฆฌ์์ค์ ์ ๊ทผํ๋ ๊ถํ ๋๋ ๋์ ์ํ ๊ฐ๋ฅ์ฑ์ ์ง๋๊ณ ์๋ ์ง ๊ฒ์ฆ - ์ ๊ทผ ๊ถํ์ ์ป๋ ์ผ
๊ทธ๋์ ๋ณดํต ์ฟ ํค / ์ธ์ / ํ ํฐ ๋ฐฉ์์ผ๋ก ํด๊ฒฐํ์ง๋ง ํด๊ฒฐ๋ฐฉ์์ ๋ํด์๋ ์๋ต.
๐ค ์ธ์ฆ ๊ณผ์ ์ ๋ค์๊ณผ ๊ฐ๋ค.

๋ก๊ทธ์ธ์ ํตํ ์ธ์ฆ ๊ตฌ์กฐ

- ์ฌ์ฉ์์ ์์ฒญ ( Request ) โ ์ธํฐ์ ํธ โ
- UsernamePasswordAuthenticationToken ์์ฑ
- ์ธ์ฆ ๋ด๋น โ ์์ด๋ - PW ( post -form ๋ฐ์ดํฐ๋ก ์์ฑ ) โ Authentication ๊ฐ์ฒด ์์ฑ - ๋ค๋ฅธ ํํฐ๋ก ์ ๋ฌํ๊ธฐ ์ํจ.
- ์ฑ๊ณต ์, ์ดํ ํ๋ก์ธ์ค ์งํ
- ์คํจ ์, throws Authentication Exception
- AuthenticationProvider์ ๊ฐ์ฒด ์ ๋ฌ
- UserDetailsService์์ Authentication ๊ฐ์ฒด๋ฅผ DB๋ด์ ์กด์ฌํ๋ ์ ์ ์์ ์กฐํ
- ์ ์ ์ธ์ ์ ์์ฑ - ๋ฆฌํด ๋ฆฌํด ๋ฆฌํด
- ์ํ๋ฆฌํฐ์ปจํ ์คํธ(์ธ๋ฉ๋ชจ๋ฆฌ) ํ๋์ ์ ์ฅ
- ์ ์ ์ธ์ ID์ ํจ๊ป ์๋ต์ ๋ณด๋ธ๋ค.
์ดํ ์ฌ์ฉ์์ ์์ฒญ(์ฟ ํค) ์์ JsessionID๋ฅผ ๊ฒ์ฆ ํ ์ ํจํ๋ค๋ฉด ์ธ์ฆ์ฒ๋ฆฌ.
์์ ํ ํ๋ก์ ํธ์ SecurityConfig
๐ค Security 3.2 ๋ฒ์ ์ด์๋ถํฐ๋ XML ์ค์ ๋ณด๋ค ์กฐ๊ธ ๋ ํธํ ์๋ฐ ๊ธฐ๋ฐ ์ด๋ ธํ ์ด์ ์ค์ (EnableWebSecurity)๋ ๊ฐ๋ฅํ๋ค.

๐ค SecurityConfig๋ WebSecurityConfigurerAdapter์ ๊ตฌํ์ฒด์ด๋ค.
๋ค์๊ณผ ๊ฐ์ด ์ปจํธ๋กค๋ฌ์์ ์ฌ์ฉ ํ ์ ์๋ ์ด๋ ธํ ์ด์ ๋ ์๋ค.

๐ค ์ด๋ ธํ ์ด์ ์ ์ํ ์ค์ ์ด๋ผ ํ์ฌ
ํฐ ์ฐจ์ด๊ฐ ์๋ ๊ฒ์ ์๋๋ฉฐ, ์ปจํธ๋กค๋ฌ ๋ณ๋ก ์๋์ configure์์ ์ธํ ํ๋ Role์ ์ปจํธ๋กค๋ฌ ๋ณ๋ก ์ธํ ํ ์ ์๋ค๋ ์ฐจ์ด์ ์ด ์๋ค.
์๋์ ์ธํ ์ด ์ปจํธ๋กค๋ฌ ์ด๋ ธํ ์ด์ ์ธํ ๊ณผ ๋์ผํ๋ค๋ฉด, ์ํ๋ฆฌํฐ ์ค์ ์ ์ํ ๋์์ ๋์ผํ๋ค.

๐ค ๋ค์์ ์์ ์ค์ธ ํ๋ก์ ํธ์ Configure ์ค์ ์ด๋ค.
์ธ์ฆ๊ณผ ์ธ๊ฐ๋ฅผ ๋์์ ํํฐ๋ก ์ฒดํฌํ๊ณ ์๋ค.

๐ค ์ด๋ฒ ํน์ target API ์ธ์ฆ ์ ๊ฑฐ ์์ ์ ๋ฌธ์ ๊ฐ ๋์๋ ๋ถ๋ถ์ ๊ฑฐ์ ๋๋ถ๋ถ์ API์ ์์์ง์ ์ธ /API/Studio/**์ ๋ถ๋ถ์ด๋ค.
๐ค ํน์ target API์ ๋ํ ์ธ์ฆ ์ ๊ฑฐ ์ค์ ๊ณผ ๊ธฐ์กด์ API ์์์ง์ ์ ๋ํ ๋ชจ๋ ์ธ์ฆ ์๊ตฌ ์ค์ ์ด ์ถฉ๋ํ๋ค.
๐ค ์์ ์์๋ ๊ฐ์ ๋ก target API์ ๋ํ ์ธ์ฆ์ ์ ๊ฑฐํ์ง๋ง API๋ด์ ๋น์ฆ๋์ค ๋ก์ง์์ ์ธ์ฆ์ ๋ฐ๋ฅธ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ์บ์นํ๋ ๋ถ๋ถ์์ ์๋ฌ๊ฐ ๋์ ์ฐํํ๋ ์์ผ๋ก ์์ ์ ์์ ํ๋ค. --> ๋ฏธ๋ฆฌ ํ์ธํ๊ณ ์์ ํ์ด์ผ ํ๋๋ฐ ์ฝ๋๋ฅผ ๊ผผ๊ผผํ ๋ณด์ง ์๊ณ ์์ ๋ถํฐ ํ๊ฒ ์์ธ..
๐ค configure ์ค์ ์์๋ JwtAuthenticationFilter ์ JwtAuthorizationFilter๋ฅผ ์ฌ์ฉํ๋๋ฐ ๋ค์์์ ๋ ๋ค ์ดํด๋ณธ๋ค.
์ธ์ฆ ํํฐ๋?

์ ๊ฐ์ด UsernamePasswordAuthenticationFilter๋ฅผ ํ์ฅํ๊ณ ์๋ค.
๐ค UsernamePasswordAuthenticationFilter๋ ์ฌ์ฉ์์ request์์ ์์ด๋์ ํจ์ค์๋๋ฅผ ํ์ฑํด์ ์ธ์ฆ ์์ฒญ(UsernamepasswordAuthentication Token์ ์์ฑ -> Authenticationmanager๋ฅผ ๊ตฌํํ ๊ฐ์ฒด์ ์ธ์ฆ ์์)์ ํ๋ค.
์ด๋,

์ ๊ฐ์ด ๊ตฌํํ๊ณ , ๋ค์๊ณผ ๊ฐ์ ๊ณผ์ ์ ๊ฑฐ์น๋ค๊ณ ๋ณด๋ฉด ๋๋ค.

// UserDetailService์ ์์๊ณผ ๊ตฌํ์ฒด๊ฐ ์กด์ฌํด์ผ ํ๋ค.
Authentication authentication = this.getAuthenticationManager().authenticate(authenticationToken);
ํ๋ก๋ฐ์ด๋๋ ์ค์ ์ฌ์ฉ์ ์ฌ๋ถ๋ฅผ ๋ฐ๋์ ์ฒดํฌํด์ผ ํ๋ค.

๐ค ์ ๊ณผ์ ์์AuthenticationManager๋ฅผ ํตํ ๋ก๊ทธ์ธ ์๋๋ UserDetailService๋ฅผ ์์๋ฐ์ PrincipalDetailService๋ฅผ ํธ์ถํ๊ณ ,
loadUserByUserName ๋ฉ์๋๋ฅผ ํตํด ์๋น์ค์ DB์ ์๋ ์ ์ ์ ์ผ์นํ๋์ง ์ฒดํฌํ๋ค.
@Service
@RequiredArgsConstructor
public class PrincipalDetailService implements UserDetailsService {
private final AuthRepository AuthRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
String loginId = username;
Account userEntity = AuthRepository.selectUserByLoginId(loginId);
if (ICNObjectUtility.isEmpty(userEntity)) {
throw new UsernameNotFoundException("UsernameNotFoundException!!");
} else {
return new PrincipalDetails(userEntity);
}
}
}
๐ค ๋ค์์ 4๋ฒ ๊ณผ์ ์ธ ์์ด๋์ ํจ์ค์๋๋ฅผ ํตํ ์ธ์ฆ ์ฑ๊ณต์์ ๋ก์ง์ด๋ค.

์์ ์ค์ธ ํ๋ก์ ํธ๋ ์ฟ ํค๋ฅผ ํตํ ์ธ์ฆ ๋ชจ๋์ ํค๋๋ฅผ ํตํ ์ธ์ฆ๋ชจ๋๋ก ๋๋ ์ ธ ์๋ค ( ์ค์ ๊ฐ properties๋ก ์ ์ด)
์ธ์ฆ ์ฑ๊ณต ์ดํ ๋ ๋์ค ์บ์ ์๋ฒ์ ํ ํฐ๊ณผ ๊ณ์ ๋ก๊ทธ์ธ ์์ด๋ ๋ฑ์ ์ธํ ํ๋ค.
// ํ ํฐ ์์ฑ
accessToken = this.jwtUtility.generateToken(principalDetails, expTmAccess);
refreshToken = this.jwtUtility.generateToken(principalDetails, expTmRefresh);
// ์ฟ ํค
accessToken = this.jwtUtility.generateToken(principalDetails, expTmAccess);
refreshToken = this.jwtUtility.generateToken(principalDetails, expTmRefresh);
// response
response.addCookie(accessCookie);
response.addCookie(refreshCookie);
// redis ์ ์ ์ฌ
redisUtility.setData(refreshToken, principalDetails.getAccount().getLoginId(), Long.valueOf(expTmRefresh));
๋ ๋์ค์ Data ์์ฑํด์ ๊ธฐ๋กํ๊ณ , ๋ฆฌํดํ๋ค.
์ธ๊ฐ ํํฐ๋?

BasicAuthenticationFilter๋ฅผ ํ์ฅํ๋ค.

์ธ์ฆ๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก ์์ ์ค์ธ ํ๋ก์ ํธ์์ properties๋ก ๊ด๋ฆฌํ๋ ์ธ์ฆ ๋ชจ๋์ ๋ฐ๋ผ ๋ถ๊ธฐ๊ฐ ๋๋๋ค. (์๋ต)
์ฌ๊ธฐ์๋ ๋ง์ฐฌ๊ฐ์ง๋ก ํค๋ ์ฟ ํค ์ธ๊ฐ ๊ฒ์ฆ์ผ๋ก ๋ณธ๋ค.
try {
// request์ ํ ํฐ์ ๊ฒ์ฆ (์ฟ ํค)
Cookie accessCookie = this.cookieUtility.getCookie(request, "accessToken");
Cookie refreshCookie = this.cookieUtility.getCookie(request, "refreshToken");
// Secret ํค๋ฅผ ํตํ JWT ๊ฒ์ฆ
loginId = JWT.require(Algorithm.HMAC512(this.Properties.getSecret())).build().verify(accessToken).getClaim("loginId").asString();
// ๋ก๊ทธ์ธ ์ฌ์ฉ์ ๊ฒ์ฆ
Account userEntity = commAuthRepository.selectUserByLoginId(loginId);
PrincipalDetails principalDetails = new PrincipalDetails(userEntity);
Authentication authentication = new UsernamePasswordAuthenticationToken(principalDetails, null, principalDetails.getAuthorities());
// security session์ ์ ๊ทผํด์ Autehntication ๊ฐ์ฒด๋ฅผ ์ ์ฅํ๋ค.
SecurityContextHolder.getContext().setAuthentication(authentication);
// ์ ์ฅํ ๊ฐ์ฒด๋ ๋ค์๊ณผ ๊ฐ์ด ๊บผ๋ด์ฌ ์ ์๋ค!
// SecurityContextHolder.getContext().getAuthentication(authentication);
// ์ฑ๊ณต์ผ ๊ฒฝ์ฐ ๋ค์ ๊ณผ์ ์งํ
chain.doFilter(request, response);
} catch (JWTVerificationException e) {
// ํ ํฐ ๊ฒ์ฆ์ ์คํจํ๊ฑฐ๋ ๋ง๋ฃ ์ธ๊ฒฝ์ฐ refresh token ๊ฒ์ฆ
refreshCookie = this.cookieUtility.getCookie(request, "refreshToken");
// redis ์๋ฒ์์ refreshToken์ด ์กด์ฌํ๋์ง ํ์ธํ๊ณ ,
String redisLoginId = redisUtility.getData(refreshToken);
// ๋ค์ ์ก์ธ์ค ํ ํฐ์ ๋ฐ๊ธํ๋ค.
String newAccessToken = this.jwtUtility.generateToken(principalDetails, expTmAccess);
Cookie newAccessCookie = this.cookieUtility.createTokenCookie("accessToken", newAccessToken, expTmRefresh);
response.addCookie(newAccessCookie);
} catch (Exception e ) {
// ์๋ต..
}
๐ค ๊ฐ์ฒด๋ฅผ ์ ์ฅํ๊ณ ๊บผ๋ด์ค๋ฉฐ ์ฌ์ฉ์์ ์ ๋ณด์ ๋ํด ๋ง์ ๊ฒ์ ์ ์ ์๊ฒ ๋๋๋ฐ,
๐ค ์ด ๊ณผ์ ์ด ์ด๋ฒ ์์ ์ฌํญ์์ ๋ง์ ๋ฌธ์ ๋ฅผ ์ผ์ผํจ ๋ถ๋ถ์ด๋ค.

ํ์ฌ ํ๋ก์ ํธ ๋ด์์๋ ๋ค์๊ณผ๊ฐ์ด ์ธ์ ์ ์ ์ฅ๋ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค๋ ์ฝ๋๊ฐ ์กด์ฌํ๋๋ฐ,
๋ฌธ์ ๋ ์ด ์ธ์ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค๋ ์ฌ์ฉ์ฒ๊ฐ

์ ๋ง ๋ง๋ค...
๐ ๋น์ฐํ ๋ด๊ฐ ์์ ํ๋ ์ธ์ฆ ์ธ๊ฐ ์๋ตํ๋ ํน์ API OPEN ์์ ์
์ฌ์ฉ์๊ฐ ์ต์ด ์ ๊ทผ -
configurer์ ์ํ filter (์ธ์ฆ ๋ฐ ์ธ๊ฐ) -
์ธ๊ฐ session ์ ์ฌ์ฉ์ ์ ๋ณด ์ ์ฅ -
controller api ํธ์ถ -
๋น์ฆ๋์ค -
์ข ๋ฃ
๋๋ ๋น์ฆ๋์ค - ( ์ฌ์ฉ์ ๊ฒ์ฆ ๋ฐ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ๋ฐํ์ผ๋ก ํ ๋น์ฆ๋์ค ๋ก์ง )
๊ณผ ๊ฐ์ ๋ฐฉ์์์ ๋ ๋ฒ์งธ ์ผ์ด์ค์ธ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ์ฐ๋ ๊ฒฝ์ฐ ๋ฌธ์ ๊ฐ ๋๋ค.
์์ ํ ์ธ์ฆ๊ณผ ์ธ๊ฐ๋ฅผ ์๋ตํ API์ ์ ๊ทผ(๋น์ฐํ ์๋ต๋์ผ๋ Session์๋ ์ฌ์ฉ์ ์ ๋ณด๊ฐ ์๋ค!) ํ๋๋ฐ, ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ๊ฒ์ฆํ๋ ๋น์ฆ๋์ค ๋ก์ง์ด ์จ์ด์๋ค๋ฉด? -> null point Exception์ ๋ฐฉ์ดํ์ง ์์ ๊ฒฝ์ฐ ๊ทธ๋๋ก 500 Error ๋ฐ์ ํน์ ๋ฐฉ์ด ์ฝ๋์ธ ๊ฒฝ์ฐ ์ ์์ ์ธ ์ ๊ทผ์ด ์๋๋ผ๋ Return์ ๋ฐ๊ธฐ ๋๋ฌธ์ด๋ค.
๋ฐ๋ผ์, target API๋ง! ๋ฐ๋์ ํ์ํ ๊ฒฝ์ฐ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ์๋ตํ๋ ์์ผ๋ก ์์ ๋ฐฉํฅ์ ์ก์๋ค.
๋๋ ๋์ผํ ๊ธฐ๋ฅ์ ํ๋ ์ ๊ท API ์์ฑ ( ํํฐ์ ๋ฒ์์์ ์ ์ธ๋ URI๋ก)
๊ทธ ์ธ.
OAuth๋ฅผ ํตํ ๋ก๊ทธ์ธ
Oauth : ๊ตฌ๊ธ, ํ์ด์ค๋ถ, ํธ์ํฐ์ ๊ฐ์ ๋ค์ํ ํ๋ซํผ์ ํน์ ํ ์ฌ์ฉ์ ๋ฐ์ดํฐ์ ์ ๊ทผํ๊ธฐ ์ํด ์ 3์ ํด๋ผ์ด์ธํธ(์ฐ๋ฆฌ์ ์๋น์ค)๊ฐ ์ฌ์ฉ์์ ์ ๊ทผ ๊ถํ์ ์์(Delegated Authorization)๋ฐ์ ์ ์๋ ํ์ค ํ๋กํ ์ฝ.
Resource Owner = ์ฌ์ฉ์
Client = Resource Server์ ์์์ ์ด์ํ๊ณ ์ ํ๋ ์๋น์ค, ๋ณดํต ๊ฐ๋ฐํ๊ณ ์ ํ๋ ์๋น์ค!
Authorization & Resource Server = ๋ณ๊ฐ ํน์ ํ๋๋ก ๊ตฌ์ฑ ๊ฐ๋ฅํ๋ฉฐ , ๊ตฌ๊ธ , ํ์ด์ค๋ถ, ์นด์นด์ค์ ๊ฐ์ด ๋ฆฌ์์ค๋ฅผ ๊ฐ์ง๊ณ ์๋ ์๋ฒ๋ฅผ ๋งํจ.

- ๋ก๊ทธ์ธ ์์ฒญ - ๊ตฌ๊ธ๊ณ์ ์ผ๋ก ๋ก๊ทธ์ธํ๊ธฐ ๋ฑ์ด ํด๋น.
- ๊ตฌ๊ธ(Authorization Server / Re - ์ค์ฌ์ As/Rs ๊ฐ ์ ๊ณตํ๋ URL์ client_id, redirect_uri , scope ๋ฑ์ ๋งค๊ฐ๋ณ์๋ฅผ ํฌํจํ์ฌ ์ ๋ฌ
- Ex )

- 3~4 ๋ก๊ทธ์ธ ํ์ด์ง ์ ๊ณต, ID / PW ์ ๊ณต
- ํด๋ผ์ด์ธํธ๊ฐ ๋น๋ํ ์ธ์ฆ ํ์ด์ง๋ก ์ด๋ํ ์ฌ์ฉ์๋ ์ ๊ณต๋ ๋ก๊ทธ์ธ ํ์ด์ง์์ ID / PW๋ก ์ธ์ฆ.
- 5~6 Authorization Code ๋ฐ๊ธ, Redirect URI๋ก Redirect ์ฒ๋ฆฌ.
- ์ธ์ฆ ์ฑ๊ณต - As๊ฐ client๊ฐ ์ ๊ณตํ redirect_uri๋ก ์ฌ์ฉ์๋ฅผ ๋์ง๋ค. + (Authorization Code ํฌํจ)
- ์ด Authorization Code๋ client๊ฐ Access Token์ ํ๋ํ๊ธฐ ์ํด ์ฌ์ฉํ๋ ์์ ์ฝ๋. (1๋ถ์ ๋ ์๋ช )
- ์ธ์ฆ ์ฑ๊ณต - As๊ฐ client๊ฐ ์ ๊ณตํ redirect_uri๋ก ์ฌ์ฉ์๋ฅผ ๋์ง๋ค. + (Authorization Code ํฌํจ)
- 7~8 client๋ ~6๊น์ง์ ๊ฒฐ๊ณผ๋ก ๋ฐ์ Authorization Code๋ฅผ As์ ์ ๋ฌํ๊ณ Access Token์ ๋ฐ๋๋ค.
- ๋ฐ๊ธ๋ฐ์ Access Token์ ์ ์ฅํ๊ณ , Rs์ ๋ฆฌ์์ค์ ์ ๊ทผ ํ ๋๋ง๋ค Access Token์ ์ฌ์ฉํ๋ค.
- ํ ํฐ ๊ฐ์ ๊ตํ์ token ์๋ํฌ์ธํธ์์ ์ด๋ฃจ์ด์ง๋ค
- ๋ฐ๊ธ๋ฐ์ Access Token์ ์ ์ฅํ๊ณ , Rs์ ๋ฆฌ์์ค์ ์ ๊ทผ ํ ๋๋ง๋ค Access Token์ ์ฌ์ฉํ๋ค.

- 9 ๋ก๊ทธ์ธ ์ฑ๊ณต.
- 10 ~ 13 ๋ฐ๊ธ๋ฐ์ ์ก์ธ์ค ํ ํฐ์ผ๋ก ๋ฆฌ์์ค ์ ๊ทผ
Authorization Code์ Implicit Grant(์๋ฌต์ ์น์ธ)
๊ธ ์ถ์ฒ : https://hudi.blog/oauth-2.0/
Authorization Code๋ฅผ ๋ฐ๊ธํ์ง ์๊ณ , ๊ณง๋ฐ๋ก Client์๊ฒ Access Token์ ๋ฐ๊ธํด์ค๋ ๋์ง ์์๊น?
์ ๊ตณ์ด Access Token์ ํ๋ํ๋ ๊ณผ์ ์ Authorization Code ๋ฐ๊ธ ๊ณผ์ ์ด ํ์ํ ๊น?
Redirect URI๋ฅผ ํตํด Authorization Code๋ฅผ ๋ฐ๊ธํ๋ ๊ณผ์ ์ด ์๋ต๋๋ค๋ฉด,
Authorization Server๊ฐ Access Token์ Client์ ์ ๋ฌํ๊ธฐ ์ํด Redirect URI๋ฅผ ํตํด์ผ ํ๋ค.
์ด๋, Redirect URI๋ฅผ ํตํด ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํ ๋ฐฉ๋ฒ์ URL ์์ฒด์ ๋ฐ์ดํฐ๋ฅผ ์ค์ด ์ ๋ฌํ๋ ๋ฐฉ๋ฒ๋ฐ์ ์กด์ฌํ์ง ์๋๋ค.
๋ธ๋ผ์ฐ์ ๋ฅผ ํตํด ๋ฐ์ดํฐ๊ฐ ๊ณง๋ฐ๋ก ๋
ธ์ถ๋๋ ๊ฒ ์ด๋ค.
ํ์ง๋ง, Access Token์ ๋ฏผ๊ฐํ ๋ฐ์ดํฐ์ด๋ค. ์ด๋ ๊ฒ ์ฝ๊ฒ ๋
ธ์ถ๋์ด์๋ ์๋๋ค.
์ด๋ฐ ๋ณด์ ์ฌ๊ณ ๋ฅผ ๋ฐฉ์ง Authorization Code๋ฅผ ์ฌ์ฉํ๋ ๊ฒ ์ด๋ค.
Redirect URI๋ฅผ ํ๋ก ํธ์๋ ์ฃผ์๋ก ์ค์ ํ์ฌ, Authorization Code๋ฅผ ํ๋ก ํธ์๋๋ก ์ ๋ฌํ๋ค.
๊ทธ๋ฆฌ๊ณ ์ด Authorization Code๋ ํ๋ก ํธ์๋์์ ๋ฐฑ์๋๋ก ์ ๋ฌ๋๋ค.
์ฝ๋๋ฅผ ์ ๋ฌ๋ฐ์
๋ฐฑ์๋๋ ๋น๋ก์ Authorization Server์ token ์๋ํฌ์ธํธ๋ก ์์ฒญํ์ฌ Access Token์ ๋ฐ๊ธํ๋ค.
์ด๋ฐ ๊ณผ์ ์ ๊ฑฐ์น๋ฉด Access Token์ด
ํญ์ ์ฐ๋ฆฌ์ ์ดํ๋ฆฌ์ผ์ด์
๊ณผ OAuth ์๋น์ค์ ๋ฐฑ์ฑ๋์ ํตํด์๋ง ์ ์ก๋๊ธฐ ๋๋ฌธ์
๊ณต๊ฒฉ์๊ฐ Access Token์ ๊ฐ๋ก์ฑ ์ ์๊ฒ๋๋ค.
Implicit Grant โ ์๋ฌต์ ์น์ธ ๋ฐฉ์ - ์ด์ ์ javaScript์์ ๋ง์ด ์ผ๋ค๊ณ ํจ.
์์ ๊ฐ์ ๋ฐฉ์ ์ธ์๋ ์๋ฌต์ ์น์ธ ๋ฐฉ์์ด ์๋ค. ๊ถํ ๋ถ์ฌ ์น์ธ ์ฝ๋ ์์ด ๋ฐ๋ก Access Token์ด ๋ฐ๊ธ๋๋ ๋ฐฉ์์ด๋ฉฐ, ๋ง๋ฃ๊ธฐ๊ฐ์ ์งง๊ฒ ์ค์ ํ์ฌ ๋์ถ ์ํ์ ์ค์ผ ํ์๊ฐ ์๋ค๊ณ ํ๋ค. - ๊ถ์ฅํ์ง ์๋ ๋ฐฉ์.
- ๋ํ Refresh Token์ฌ์ฉ์ด ๋ถ๊ฐ๋ฅํ๋ค.
- ์๋ต-ํจ์จ์ด ์ข์ง๋ง Access token์ด URL๋ก ์ ๋ฌ๋๋ค๋ ๋จ์ ์ด ์๋ค.

Authorization Code์์๋ ์ ๋ขฐ ํ ์ ์๋ back Channel์์ ๋ฐํ ๋ฐ์ง๋ง, Implicit Grant๋ฐฉ์์์๋ Access token์ด URL์ ์ง์ ๋ฐํ (RedirectURL๋ก ์ ๋ฌ๋๋ ๊ฒ.)
โ ๋.
์ฐธ์กฐ : https://www.youtube.com/watch?v=aEk-7RjBKwQ
์ฐธ์กฐ : https://hudi.blog/oauth-2.0/
OAuth 2.0 ๊ฐ๋ ๊ณผ ๋์์๋ฆฌ
2022๋ 07์ 13์ผ์ ์์ฑํ ๊ธ์ ๋ณด์ถฉํ์ฌ ์๋ก ํฌ์คํ ํ ๊ธ์ด๋ค. OAuth ๋ฑ์ฅ ๋ฐฐ๊ฒฝ ์ฐ๋ฆฌ์ ์๋น์ค๊ฐ ์ฌ์ฉ์๋ฅผ ๋์ ํ์ฌ ๊ตฌ๊ธ์ ์บ๋ฆฐ๋์ ์ผ์ ์ ์ถ๊ฐํ๊ฑฐ๋, ํ์ด์ค๋ถ, ํธ์ํฐ์ ๊ธ์ ๋จ๊ธฐ๋ ๊ธฐ๋ฅ์
hudi.blog
์ฐธ์กฐ : https://blog.naver.com/mds_datasecurity/222182943542
OAuth 2.0 ๋์ ๋ฐฉ์์ ์ดํด
OAuth 2.0(Open Authorization 2.0, OAuth2)์ ์ธ์ฆ์ ์ํ ๊ฐ๋ฐฉํ ํ์ค ํ๋กํ ์ฝ์ ๋๋ค. ์ด ํ๋กํ ...
blog.naver.com
์ฐธ์กฐ : https://www.youtube.com/watch?v=ZEaJsa5dwNY
'JAVA > SPRING' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Spring] @Valid , @Validated, BindingResult (0) | 2023.06.29 |
---|---|
[Spring] Spring / Spring boot ํน์ง ๊ฐ๋จ ์ ๋ฆฌ. (0) | 2023.01.11 |
[NAVER maps ๊ธธ ์ฐพ๊ธฐ] springboot + webClient ๋ก API ํธ์ถ (0) | 2022.09.02 |
springBoot / mapstruct (0) | 2022.06.08 |
spring boot / H2 DB ์ธํ (0) | 2022.05.29 |
Security docs :
Spring Security
Spring Security is a powerful and highly customizable authentication and access-control framework. It is the de-facto standard for securing Spring-based applications. Spring Security is a framework that focuses on providing both authentication and authoriz
spring.io
๐บ ์ด๊ฑฐ ์ ? ํ๋ก์ ํธ ์งํ ์ค ํน์ API๋ฅผ ์ธ๋ถ์์ ์ธ ์ ์๋๋ก ์ธ์ฆ๊ณผ์ ์ ์ ๊ฑฐํด๋ฌ๋ผ๋ ์์ฒญ์ด ์์๊ณ , ์ ๊ฑฐ ํ ํ๋ก์ ํธ๋ฅผ ์คํ ์ด์ง ์๋ฒ์์ ๊ธฐ๋
-> API๋ ์์ ๋กญ๊ฒ ์ธ ์ ์์์ผ๋, ๊ด๋ จ๋ ๋ด๋ถ ๋ฉ์๋์์ ์ธ์ฆ์ด ์๋ ๊ฒฝ์ฐ ํน์ ๊ธฐ๋ฅ์ ์ฌ์ฉํ์ง ๋ชปํ๋ ์ํฉ์ด ๋ฐ์.
Security ์ ์ธ์ฆ์ ๋ํด ์ ๋ฆฌ ํ๊ณ ๋์ด๊ฐ๊ธฐ๋ก ํจ.
์์ ํ ํ๋ก์ ํธ ๋ฒ์
Spring-boot :
- Maven: org.springframework.security.oauth:spring-security-oauth2:2.3.4.RELEASE
- Maven: org.springframework.security:spring-security-config:5.5.1
- Maven: org.springframework.security:spring-security-core:5.5.1
- Maven: org.springframework.security:spring-security-crypto:5.5.1
- Maven: org.springframework.security:spring-security-web:5.5.1
JAVA : 1.8
Security & Oauth :
- Maven: org.springframework.security.oauth:spring-security-oauth2:2.3.4.RELEASE
- -> SPRING SECURITY 5.0๋ถํฐ 2.0๋ ๋ฒ์ ์ฌ์ฉ ๊ฐ๋ฅ.
- Maven: org.springframework.security:spring-security-config:5.5.1
- Maven: org.springframework.security:spring-security-core:5.5.1
- Maven: org.springframework.security:spring-security-crypto:5.5.1
- Maven: org.springframework.security:spring-security-web:5.5.1

Spring Security์ ์ ๊ณต ๊ธฐ๋ฅ
- Servlet API ํตํฉ
- Spring Web MVC์์ ์ ํ์ ํตํฉ
- ์ธ์ฆ ๊ถํ ๋ถ์ฌ๋ฅผ ํฌ๊ด์ ๋ก ํ์ฅํ๋ฉฐ ์ง์
- ์ธ์ ๊ณ ์ , clickjacking, ์ฌ์ดํธ๊ฐ ์์ฒญ ์์กฐ(CSRF) ๋ฐฉ์ง
์น ๊ธฐ๋ฐ ์ธ์ฆ ๋ฐ ์ธ๊ฐ๋ฅผ ํธํ๊ฒ ๊ตฌํํ๋๋ก ํจ.
๐ค stateless ํ HTTP์์์ ์ธ์ฆ ์ธ๊ฐ๊ฐ ์๋ค๋ฉด ๋น๋ฐ๋ฒํธ์ ์์ด๋๋ฅผ ๊ณ์ ์ ๋ ฅํด์ผ ํ๋ ๋ถ์์ฌ๊ฐ ์๊ธธ ์ ๋์๋ค.
์ธ์ฆ? : ์ฌ์ฉ์์ ์ ์ ํ์ธ
์ธ๊ฐ? : ์ฌ์ฉ์๊ฐ ํน์ ๋ฆฌ์์ค์ ์ ๊ทผํ๋ ๊ถํ ๋๋ ๋์ ์ํ ๊ฐ๋ฅ์ฑ์ ์ง๋๊ณ ์๋ ์ง ๊ฒ์ฆ - ์ ๊ทผ ๊ถํ์ ์ป๋ ์ผ
๊ทธ๋์ ๋ณดํต ์ฟ ํค / ์ธ์ / ํ ํฐ ๋ฐฉ์์ผ๋ก ํด๊ฒฐํ์ง๋ง ํด๊ฒฐ๋ฐฉ์์ ๋ํด์๋ ์๋ต.
๐ค ์ธ์ฆ ๊ณผ์ ์ ๋ค์๊ณผ ๊ฐ๋ค.

๋ก๊ทธ์ธ์ ํตํ ์ธ์ฆ ๊ตฌ์กฐ

- ์ฌ์ฉ์์ ์์ฒญ ( Request ) โ ์ธํฐ์ ํธ โ
- UsernamePasswordAuthenticationToken ์์ฑ
- ์ธ์ฆ ๋ด๋น โ ์์ด๋ - PW ( post -form ๋ฐ์ดํฐ๋ก ์์ฑ ) โ Authentication ๊ฐ์ฒด ์์ฑ - ๋ค๋ฅธ ํํฐ๋ก ์ ๋ฌํ๊ธฐ ์ํจ.
- ์ฑ๊ณต ์, ์ดํ ํ๋ก์ธ์ค ์งํ
- ์คํจ ์, throws Authentication Exception
- AuthenticationProvider์ ๊ฐ์ฒด ์ ๋ฌ
- UserDetailsService์์ Authentication ๊ฐ์ฒด๋ฅผ DB๋ด์ ์กด์ฌํ๋ ์ ์ ์์ ์กฐํ
- ์ ์ ์ธ์ ์ ์์ฑ - ๋ฆฌํด ๋ฆฌํด ๋ฆฌํด
- ์ํ๋ฆฌํฐ์ปจํ ์คํธ(์ธ๋ฉ๋ชจ๋ฆฌ) ํ๋์ ์ ์ฅ
- ์ ์ ์ธ์ ID์ ํจ๊ป ์๋ต์ ๋ณด๋ธ๋ค.
์ดํ ์ฌ์ฉ์์ ์์ฒญ(์ฟ ํค) ์์ JsessionID๋ฅผ ๊ฒ์ฆ ํ ์ ํจํ๋ค๋ฉด ์ธ์ฆ์ฒ๋ฆฌ.
์์ ํ ํ๋ก์ ํธ์ SecurityConfig
๐ค Security 3.2 ๋ฒ์ ์ด์๋ถํฐ๋ XML ์ค์ ๋ณด๋ค ์กฐ๊ธ ๋ ํธํ ์๋ฐ ๊ธฐ๋ฐ ์ด๋ ธํ ์ด์ ์ค์ (EnableWebSecurity)๋ ๊ฐ๋ฅํ๋ค.

๐ค SecurityConfig๋ WebSecurityConfigurerAdapter์ ๊ตฌํ์ฒด์ด๋ค.
๋ค์๊ณผ ๊ฐ์ด ์ปจํธ๋กค๋ฌ์์ ์ฌ์ฉ ํ ์ ์๋ ์ด๋ ธํ ์ด์ ๋ ์๋ค.

๐ค ์ด๋ ธํ ์ด์ ์ ์ํ ์ค์ ์ด๋ผ ํ์ฌ
ํฐ ์ฐจ์ด๊ฐ ์๋ ๊ฒ์ ์๋๋ฉฐ, ์ปจํธ๋กค๋ฌ ๋ณ๋ก ์๋์ configure์์ ์ธํ ํ๋ Role์ ์ปจํธ๋กค๋ฌ ๋ณ๋ก ์ธํ ํ ์ ์๋ค๋ ์ฐจ์ด์ ์ด ์๋ค.
์๋์ ์ธํ ์ด ์ปจํธ๋กค๋ฌ ์ด๋ ธํ ์ด์ ์ธํ ๊ณผ ๋์ผํ๋ค๋ฉด, ์ํ๋ฆฌํฐ ์ค์ ์ ์ํ ๋์์ ๋์ผํ๋ค.

๐ค ๋ค์์ ์์ ์ค์ธ ํ๋ก์ ํธ์ Configure ์ค์ ์ด๋ค.
์ธ์ฆ๊ณผ ์ธ๊ฐ๋ฅผ ๋์์ ํํฐ๋ก ์ฒดํฌํ๊ณ ์๋ค.

๐ค ์ด๋ฒ ํน์ target API ์ธ์ฆ ์ ๊ฑฐ ์์ ์ ๋ฌธ์ ๊ฐ ๋์๋ ๋ถ๋ถ์ ๊ฑฐ์ ๋๋ถ๋ถ์ API์ ์์์ง์ ์ธ /API/Studio/**์ ๋ถ๋ถ์ด๋ค.
๐ค ํน์ target API์ ๋ํ ์ธ์ฆ ์ ๊ฑฐ ์ค์ ๊ณผ ๊ธฐ์กด์ API ์์์ง์ ์ ๋ํ ๋ชจ๋ ์ธ์ฆ ์๊ตฌ ์ค์ ์ด ์ถฉ๋ํ๋ค.
๐ค ์์ ์์๋ ๊ฐ์ ๋ก target API์ ๋ํ ์ธ์ฆ์ ์ ๊ฑฐํ์ง๋ง API๋ด์ ๋น์ฆ๋์ค ๋ก์ง์์ ์ธ์ฆ์ ๋ฐ๋ฅธ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ์บ์นํ๋ ๋ถ๋ถ์์ ์๋ฌ๊ฐ ๋์ ์ฐํํ๋ ์์ผ๋ก ์์ ์ ์์ ํ๋ค. --> ๋ฏธ๋ฆฌ ํ์ธํ๊ณ ์์ ํ์ด์ผ ํ๋๋ฐ ์ฝ๋๋ฅผ ๊ผผ๊ผผํ ๋ณด์ง ์๊ณ ์์ ๋ถํฐ ํ๊ฒ ์์ธ..
๐ค configure ์ค์ ์์๋ JwtAuthenticationFilter ์ JwtAuthorizationFilter๋ฅผ ์ฌ์ฉํ๋๋ฐ ๋ค์์์ ๋ ๋ค ์ดํด๋ณธ๋ค.
์ธ์ฆ ํํฐ๋?

์ ๊ฐ์ด UsernamePasswordAuthenticationFilter๋ฅผ ํ์ฅํ๊ณ ์๋ค.
๐ค UsernamePasswordAuthenticationFilter๋ ์ฌ์ฉ์์ request์์ ์์ด๋์ ํจ์ค์๋๋ฅผ ํ์ฑํด์ ์ธ์ฆ ์์ฒญ(UsernamepasswordAuthentication Token์ ์์ฑ -> Authenticationmanager๋ฅผ ๊ตฌํํ ๊ฐ์ฒด์ ์ธ์ฆ ์์)์ ํ๋ค.
์ด๋,

์ ๊ฐ์ด ๊ตฌํํ๊ณ , ๋ค์๊ณผ ๊ฐ์ ๊ณผ์ ์ ๊ฑฐ์น๋ค๊ณ ๋ณด๋ฉด ๋๋ค.

// UserDetailService์ ์์๊ณผ ๊ตฌํ์ฒด๊ฐ ์กด์ฌํด์ผ ํ๋ค.
Authentication authentication = this.getAuthenticationManager().authenticate(authenticationToken);
ํ๋ก๋ฐ์ด๋๋ ์ค์ ์ฌ์ฉ์ ์ฌ๋ถ๋ฅผ ๋ฐ๋์ ์ฒดํฌํด์ผ ํ๋ค.

๐ค ์ ๊ณผ์ ์์AuthenticationManager๋ฅผ ํตํ ๋ก๊ทธ์ธ ์๋๋ UserDetailService๋ฅผ ์์๋ฐ์ PrincipalDetailService๋ฅผ ํธ์ถํ๊ณ ,
loadUserByUserName ๋ฉ์๋๋ฅผ ํตํด ์๋น์ค์ DB์ ์๋ ์ ์ ์ ์ผ์นํ๋์ง ์ฒดํฌํ๋ค.
@Service
@RequiredArgsConstructor
public class PrincipalDetailService implements UserDetailsService {
private final AuthRepository AuthRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
String loginId = username;
Account userEntity = AuthRepository.selectUserByLoginId(loginId);
if (ICNObjectUtility.isEmpty(userEntity)) {
throw new UsernameNotFoundException("UsernameNotFoundException!!");
} else {
return new PrincipalDetails(userEntity);
}
}
}
๐ค ๋ค์์ 4๋ฒ ๊ณผ์ ์ธ ์์ด๋์ ํจ์ค์๋๋ฅผ ํตํ ์ธ์ฆ ์ฑ๊ณต์์ ๋ก์ง์ด๋ค.

์์ ์ค์ธ ํ๋ก์ ํธ๋ ์ฟ ํค๋ฅผ ํตํ ์ธ์ฆ ๋ชจ๋์ ํค๋๋ฅผ ํตํ ์ธ์ฆ๋ชจ๋๋ก ๋๋ ์ ธ ์๋ค ( ์ค์ ๊ฐ properties๋ก ์ ์ด)
์ธ์ฆ ์ฑ๊ณต ์ดํ ๋ ๋์ค ์บ์ ์๋ฒ์ ํ ํฐ๊ณผ ๊ณ์ ๋ก๊ทธ์ธ ์์ด๋ ๋ฑ์ ์ธํ ํ๋ค.
// ํ ํฐ ์์ฑ
accessToken = this.jwtUtility.generateToken(principalDetails, expTmAccess);
refreshToken = this.jwtUtility.generateToken(principalDetails, expTmRefresh);
// ์ฟ ํค
accessToken = this.jwtUtility.generateToken(principalDetails, expTmAccess);
refreshToken = this.jwtUtility.generateToken(principalDetails, expTmRefresh);
// response
response.addCookie(accessCookie);
response.addCookie(refreshCookie);
// redis ์ ์ ์ฌ
redisUtility.setData(refreshToken, principalDetails.getAccount().getLoginId(), Long.valueOf(expTmRefresh));
๋ ๋์ค์ Data ์์ฑํด์ ๊ธฐ๋กํ๊ณ , ๋ฆฌํดํ๋ค.
์ธ๊ฐ ํํฐ๋?

BasicAuthenticationFilter๋ฅผ ํ์ฅํ๋ค.

์ธ์ฆ๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก ์์ ์ค์ธ ํ๋ก์ ํธ์์ properties๋ก ๊ด๋ฆฌํ๋ ์ธ์ฆ ๋ชจ๋์ ๋ฐ๋ผ ๋ถ๊ธฐ๊ฐ ๋๋๋ค. (์๋ต)
์ฌ๊ธฐ์๋ ๋ง์ฐฌ๊ฐ์ง๋ก ํค๋ ์ฟ ํค ์ธ๊ฐ ๊ฒ์ฆ์ผ๋ก ๋ณธ๋ค.
try {
// request์ ํ ํฐ์ ๊ฒ์ฆ (์ฟ ํค)
Cookie accessCookie = this.cookieUtility.getCookie(request, "accessToken");
Cookie refreshCookie = this.cookieUtility.getCookie(request, "refreshToken");
// Secret ํค๋ฅผ ํตํ JWT ๊ฒ์ฆ
loginId = JWT.require(Algorithm.HMAC512(this.Properties.getSecret())).build().verify(accessToken).getClaim("loginId").asString();
// ๋ก๊ทธ์ธ ์ฌ์ฉ์ ๊ฒ์ฆ
Account userEntity = commAuthRepository.selectUserByLoginId(loginId);
PrincipalDetails principalDetails = new PrincipalDetails(userEntity);
Authentication authentication = new UsernamePasswordAuthenticationToken(principalDetails, null, principalDetails.getAuthorities());
// security session์ ์ ๊ทผํด์ Autehntication ๊ฐ์ฒด๋ฅผ ์ ์ฅํ๋ค.
SecurityContextHolder.getContext().setAuthentication(authentication);
// ์ ์ฅํ ๊ฐ์ฒด๋ ๋ค์๊ณผ ๊ฐ์ด ๊บผ๋ด์ฌ ์ ์๋ค!
// SecurityContextHolder.getContext().getAuthentication(authentication);
// ์ฑ๊ณต์ผ ๊ฒฝ์ฐ ๋ค์ ๊ณผ์ ์งํ
chain.doFilter(request, response);
} catch (JWTVerificationException e) {
// ํ ํฐ ๊ฒ์ฆ์ ์คํจํ๊ฑฐ๋ ๋ง๋ฃ ์ธ๊ฒฝ์ฐ refresh token ๊ฒ์ฆ
refreshCookie = this.cookieUtility.getCookie(request, "refreshToken");
// redis ์๋ฒ์์ refreshToken์ด ์กด์ฌํ๋์ง ํ์ธํ๊ณ ,
String redisLoginId = redisUtility.getData(refreshToken);
// ๋ค์ ์ก์ธ์ค ํ ํฐ์ ๋ฐ๊ธํ๋ค.
String newAccessToken = this.jwtUtility.generateToken(principalDetails, expTmAccess);
Cookie newAccessCookie = this.cookieUtility.createTokenCookie("accessToken", newAccessToken, expTmRefresh);
response.addCookie(newAccessCookie);
} catch (Exception e ) {
// ์๋ต..
}
๐ค ๊ฐ์ฒด๋ฅผ ์ ์ฅํ๊ณ ๊บผ๋ด์ค๋ฉฐ ์ฌ์ฉ์์ ์ ๋ณด์ ๋ํด ๋ง์ ๊ฒ์ ์ ์ ์๊ฒ ๋๋๋ฐ,
๐ค ์ด ๊ณผ์ ์ด ์ด๋ฒ ์์ ์ฌํญ์์ ๋ง์ ๋ฌธ์ ๋ฅผ ์ผ์ผํจ ๋ถ๋ถ์ด๋ค.

ํ์ฌ ํ๋ก์ ํธ ๋ด์์๋ ๋ค์๊ณผ๊ฐ์ด ์ธ์ ์ ์ ์ฅ๋ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค๋ ์ฝ๋๊ฐ ์กด์ฌํ๋๋ฐ,
๋ฌธ์ ๋ ์ด ์ธ์ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค๋ ์ฌ์ฉ์ฒ๊ฐ

์ ๋ง ๋ง๋ค...
๐ ๋น์ฐํ ๋ด๊ฐ ์์ ํ๋ ์ธ์ฆ ์ธ๊ฐ ์๋ตํ๋ ํน์ API OPEN ์์ ์
์ฌ์ฉ์๊ฐ ์ต์ด ์ ๊ทผ -
configurer์ ์ํ filter (์ธ์ฆ ๋ฐ ์ธ๊ฐ) -
์ธ๊ฐ session ์ ์ฌ์ฉ์ ์ ๋ณด ์ ์ฅ -
controller api ํธ์ถ -
๋น์ฆ๋์ค -
์ข ๋ฃ
๋๋ ๋น์ฆ๋์ค - ( ์ฌ์ฉ์ ๊ฒ์ฆ ๋ฐ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ๋ฐํ์ผ๋ก ํ ๋น์ฆ๋์ค ๋ก์ง )
๊ณผ ๊ฐ์ ๋ฐฉ์์์ ๋ ๋ฒ์งธ ์ผ์ด์ค์ธ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ์ฐ๋ ๊ฒฝ์ฐ ๋ฌธ์ ๊ฐ ๋๋ค.
์์ ํ ์ธ์ฆ๊ณผ ์ธ๊ฐ๋ฅผ ์๋ตํ API์ ์ ๊ทผ(๋น์ฐํ ์๋ต๋์ผ๋ Session์๋ ์ฌ์ฉ์ ์ ๋ณด๊ฐ ์๋ค!) ํ๋๋ฐ, ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ๊ฒ์ฆํ๋ ๋น์ฆ๋์ค ๋ก์ง์ด ์จ์ด์๋ค๋ฉด? -> null point Exception์ ๋ฐฉ์ดํ์ง ์์ ๊ฒฝ์ฐ ๊ทธ๋๋ก 500 Error ๋ฐ์ ํน์ ๋ฐฉ์ด ์ฝ๋์ธ ๊ฒฝ์ฐ ์ ์์ ์ธ ์ ๊ทผ์ด ์๋๋ผ๋ Return์ ๋ฐ๊ธฐ ๋๋ฌธ์ด๋ค.
๋ฐ๋ผ์, target API๋ง! ๋ฐ๋์ ํ์ํ ๊ฒฝ์ฐ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ์๋ตํ๋ ์์ผ๋ก ์์ ๋ฐฉํฅ์ ์ก์๋ค.
๋๋ ๋์ผํ ๊ธฐ๋ฅ์ ํ๋ ์ ๊ท API ์์ฑ ( ํํฐ์ ๋ฒ์์์ ์ ์ธ๋ URI๋ก)
๊ทธ ์ธ.
OAuth๋ฅผ ํตํ ๋ก๊ทธ์ธ
Oauth : ๊ตฌ๊ธ, ํ์ด์ค๋ถ, ํธ์ํฐ์ ๊ฐ์ ๋ค์ํ ํ๋ซํผ์ ํน์ ํ ์ฌ์ฉ์ ๋ฐ์ดํฐ์ ์ ๊ทผํ๊ธฐ ์ํด ์ 3์ ํด๋ผ์ด์ธํธ(์ฐ๋ฆฌ์ ์๋น์ค)๊ฐ ์ฌ์ฉ์์ ์ ๊ทผ ๊ถํ์ ์์(Delegated Authorization)๋ฐ์ ์ ์๋ ํ์ค ํ๋กํ ์ฝ.
Resource Owner = ์ฌ์ฉ์
Client = Resource Server์ ์์์ ์ด์ํ๊ณ ์ ํ๋ ์๋น์ค, ๋ณดํต ๊ฐ๋ฐํ๊ณ ์ ํ๋ ์๋น์ค!
Authorization & Resource Server = ๋ณ๊ฐ ํน์ ํ๋๋ก ๊ตฌ์ฑ ๊ฐ๋ฅํ๋ฉฐ , ๊ตฌ๊ธ , ํ์ด์ค๋ถ, ์นด์นด์ค์ ๊ฐ์ด ๋ฆฌ์์ค๋ฅผ ๊ฐ์ง๊ณ ์๋ ์๋ฒ๋ฅผ ๋งํจ.

- ๋ก๊ทธ์ธ ์์ฒญ - ๊ตฌ๊ธ๊ณ์ ์ผ๋ก ๋ก๊ทธ์ธํ๊ธฐ ๋ฑ์ด ํด๋น.
- ๊ตฌ๊ธ(Authorization Server / Re - ์ค์ฌ์ As/Rs ๊ฐ ์ ๊ณตํ๋ URL์ client_id, redirect_uri , scope ๋ฑ์ ๋งค๊ฐ๋ณ์๋ฅผ ํฌํจํ์ฌ ์ ๋ฌ
- Ex )

- 3~4 ๋ก๊ทธ์ธ ํ์ด์ง ์ ๊ณต, ID / PW ์ ๊ณต
- ํด๋ผ์ด์ธํธ๊ฐ ๋น๋ํ ์ธ์ฆ ํ์ด์ง๋ก ์ด๋ํ ์ฌ์ฉ์๋ ์ ๊ณต๋ ๋ก๊ทธ์ธ ํ์ด์ง์์ ID / PW๋ก ์ธ์ฆ.
- 5~6 Authorization Code ๋ฐ๊ธ, Redirect URI๋ก Redirect ์ฒ๋ฆฌ.
- ์ธ์ฆ ์ฑ๊ณต - As๊ฐ client๊ฐ ์ ๊ณตํ redirect_uri๋ก ์ฌ์ฉ์๋ฅผ ๋์ง๋ค. + (Authorization Code ํฌํจ)
- ์ด Authorization Code๋ client๊ฐ Access Token์ ํ๋ํ๊ธฐ ์ํด ์ฌ์ฉํ๋ ์์ ์ฝ๋. (1๋ถ์ ๋ ์๋ช )
- ์ธ์ฆ ์ฑ๊ณต - As๊ฐ client๊ฐ ์ ๊ณตํ redirect_uri๋ก ์ฌ์ฉ์๋ฅผ ๋์ง๋ค. + (Authorization Code ํฌํจ)
- 7~8 client๋ ~6๊น์ง์ ๊ฒฐ๊ณผ๋ก ๋ฐ์ Authorization Code๋ฅผ As์ ์ ๋ฌํ๊ณ Access Token์ ๋ฐ๋๋ค.
- ๋ฐ๊ธ๋ฐ์ Access Token์ ์ ์ฅํ๊ณ , Rs์ ๋ฆฌ์์ค์ ์ ๊ทผ ํ ๋๋ง๋ค Access Token์ ์ฌ์ฉํ๋ค.
- ํ ํฐ ๊ฐ์ ๊ตํ์ token ์๋ํฌ์ธํธ์์ ์ด๋ฃจ์ด์ง๋ค
- ๋ฐ๊ธ๋ฐ์ Access Token์ ์ ์ฅํ๊ณ , Rs์ ๋ฆฌ์์ค์ ์ ๊ทผ ํ ๋๋ง๋ค Access Token์ ์ฌ์ฉํ๋ค.

- 9 ๋ก๊ทธ์ธ ์ฑ๊ณต.
- 10 ~ 13 ๋ฐ๊ธ๋ฐ์ ์ก์ธ์ค ํ ํฐ์ผ๋ก ๋ฆฌ์์ค ์ ๊ทผ
Authorization Code์ Implicit Grant(์๋ฌต์ ์น์ธ)
๊ธ ์ถ์ฒ : https://hudi.blog/oauth-2.0/
Authorization Code๋ฅผ ๋ฐ๊ธํ์ง ์๊ณ , ๊ณง๋ฐ๋ก Client์๊ฒ Access Token์ ๋ฐ๊ธํด์ค๋ ๋์ง ์์๊น?
์ ๊ตณ์ด Access Token์ ํ๋ํ๋ ๊ณผ์ ์ Authorization Code ๋ฐ๊ธ ๊ณผ์ ์ด ํ์ํ ๊น?
Redirect URI๋ฅผ ํตํด Authorization Code๋ฅผ ๋ฐ๊ธํ๋ ๊ณผ์ ์ด ์๋ต๋๋ค๋ฉด,
Authorization Server๊ฐ Access Token์ Client์ ์ ๋ฌํ๊ธฐ ์ํด Redirect URI๋ฅผ ํตํด์ผ ํ๋ค.
์ด๋, Redirect URI๋ฅผ ํตํด ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํ ๋ฐฉ๋ฒ์ URL ์์ฒด์ ๋ฐ์ดํฐ๋ฅผ ์ค์ด ์ ๋ฌํ๋ ๋ฐฉ๋ฒ๋ฐ์ ์กด์ฌํ์ง ์๋๋ค.
๋ธ๋ผ์ฐ์ ๋ฅผ ํตํด ๋ฐ์ดํฐ๊ฐ ๊ณง๋ฐ๋ก ๋
ธ์ถ๋๋ ๊ฒ ์ด๋ค.
ํ์ง๋ง, Access Token์ ๋ฏผ๊ฐํ ๋ฐ์ดํฐ์ด๋ค. ์ด๋ ๊ฒ ์ฝ๊ฒ ๋
ธ์ถ๋์ด์๋ ์๋๋ค.
์ด๋ฐ ๋ณด์ ์ฌ๊ณ ๋ฅผ ๋ฐฉ์ง Authorization Code๋ฅผ ์ฌ์ฉํ๋ ๊ฒ ์ด๋ค.
Redirect URI๋ฅผ ํ๋ก ํธ์๋ ์ฃผ์๋ก ์ค์ ํ์ฌ, Authorization Code๋ฅผ ํ๋ก ํธ์๋๋ก ์ ๋ฌํ๋ค.
๊ทธ๋ฆฌ๊ณ ์ด Authorization Code๋ ํ๋ก ํธ์๋์์ ๋ฐฑ์๋๋ก ์ ๋ฌ๋๋ค.
์ฝ๋๋ฅผ ์ ๋ฌ๋ฐ์
๋ฐฑ์๋๋ ๋น๋ก์ Authorization Server์ token ์๋ํฌ์ธํธ๋ก ์์ฒญํ์ฌ Access Token์ ๋ฐ๊ธํ๋ค.
์ด๋ฐ ๊ณผ์ ์ ๊ฑฐ์น๋ฉด Access Token์ด
ํญ์ ์ฐ๋ฆฌ์ ์ดํ๋ฆฌ์ผ์ด์
๊ณผ OAuth ์๋น์ค์ ๋ฐฑ์ฑ๋์ ํตํด์๋ง ์ ์ก๋๊ธฐ ๋๋ฌธ์
๊ณต๊ฒฉ์๊ฐ Access Token์ ๊ฐ๋ก์ฑ ์ ์๊ฒ๋๋ค.
Implicit Grant โ ์๋ฌต์ ์น์ธ ๋ฐฉ์ - ์ด์ ์ javaScript์์ ๋ง์ด ์ผ๋ค๊ณ ํจ.
์์ ๊ฐ์ ๋ฐฉ์ ์ธ์๋ ์๋ฌต์ ์น์ธ ๋ฐฉ์์ด ์๋ค. ๊ถํ ๋ถ์ฌ ์น์ธ ์ฝ๋ ์์ด ๋ฐ๋ก Access Token์ด ๋ฐ๊ธ๋๋ ๋ฐฉ์์ด๋ฉฐ, ๋ง๋ฃ๊ธฐ๊ฐ์ ์งง๊ฒ ์ค์ ํ์ฌ ๋์ถ ์ํ์ ์ค์ผ ํ์๊ฐ ์๋ค๊ณ ํ๋ค. - ๊ถ์ฅํ์ง ์๋ ๋ฐฉ์.
- ๋ํ Refresh Token์ฌ์ฉ์ด ๋ถ๊ฐ๋ฅํ๋ค.
- ์๋ต-ํจ์จ์ด ์ข์ง๋ง Access token์ด URL๋ก ์ ๋ฌ๋๋ค๋ ๋จ์ ์ด ์๋ค.

Authorization Code์์๋ ์ ๋ขฐ ํ ์ ์๋ back Channel์์ ๋ฐํ ๋ฐ์ง๋ง, Implicit Grant๋ฐฉ์์์๋ Access token์ด URL์ ์ง์ ๋ฐํ (RedirectURL๋ก ์ ๋ฌ๋๋ ๊ฒ.)
โ ๋.
์ฐธ์กฐ : https://www.youtube.com/watch?v=aEk-7RjBKwQ
์ฐธ์กฐ : https://hudi.blog/oauth-2.0/
OAuth 2.0 ๊ฐ๋ ๊ณผ ๋์์๋ฆฌ
2022๋ 07์ 13์ผ์ ์์ฑํ ๊ธ์ ๋ณด์ถฉํ์ฌ ์๋ก ํฌ์คํ ํ ๊ธ์ด๋ค. OAuth ๋ฑ์ฅ ๋ฐฐ๊ฒฝ ์ฐ๋ฆฌ์ ์๋น์ค๊ฐ ์ฌ์ฉ์๋ฅผ ๋์ ํ์ฌ ๊ตฌ๊ธ์ ์บ๋ฆฐ๋์ ์ผ์ ์ ์ถ๊ฐํ๊ฑฐ๋, ํ์ด์ค๋ถ, ํธ์ํฐ์ ๊ธ์ ๋จ๊ธฐ๋ ๊ธฐ๋ฅ์
hudi.blog
์ฐธ์กฐ : https://blog.naver.com/mds_datasecurity/222182943542
OAuth 2.0 ๋์ ๋ฐฉ์์ ์ดํด
OAuth 2.0(Open Authorization 2.0, OAuth2)์ ์ธ์ฆ์ ์ํ ๊ฐ๋ฐฉํ ํ์ค ํ๋กํ ์ฝ์ ๋๋ค. ์ด ํ๋กํ ...
blog.naver.com
์ฐธ์กฐ : https://www.youtube.com/watch?v=ZEaJsa5dwNY
'JAVA > SPRING' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Spring] @Valid , @Validated, BindingResult (0) | 2023.06.29 |
---|---|
[Spring] Spring / Spring boot ํน์ง ๊ฐ๋จ ์ ๋ฆฌ. (0) | 2023.01.11 |
[NAVER maps ๊ธธ ์ฐพ๊ธฐ] springboot + webClient ๋ก API ํธ์ถ (0) | 2022.09.02 |
springBoot / mapstruct (0) | 2022.06.08 |
spring boot / H2 DB ์ธํ (0) | 2022.05.29 |