Java/공부

세션과 JWT토큰에 대해서(Refresh Token) //나의 코드 확인하기

Yim_Ha_Eun 2024. 10. 21. 19:08

쿠키 ?: 서버가 사용자의 데이터를 브라우저에 넣음 브라우저(request)-><-(response)서버  

response시, 모든 데이터와 사용자가 찾던 정보들을 response하는데,

이때 쿠키도 request,response를 반복하며 저장되고 쓰인다.

유효기간이 있다. 인증뿐만아니라 여러 정보들을 저장할 수 있다.

 

세션과 토큰

HTTP(웹사이트를 이용할 때 쓰는 프로토콜=stateless) 

**stateless? 서버로 가는 모든 요청이 이전 request와 독립적이다.(메모리X)

request 이후, 서버는 정보를 저장하지 않음(즉, 요청할 때마다 세션을 이용해 사용자가 누구인지 알려야함)

ex)로그인

세션ID는 쿠키를 통해 DB-> Server->Browser(저장) 같은 웹사이트 내 다른 페이지로 이동하면 브라우저는 세션ID를 갖고 있는 쿠키를 서버에 보냄(자동) 서버는 세션ID와 함께 보내져오는 쿠키를 확인하고, 그 세션ID를 갖고 DB에서 유저를 찾음.

-> "환영합니다"

이후 다른 페이지로 이동하면, 이런 확인 동작이 계속 반복된다.

쿠키는 세션ID를 전달하기 위한 매개체일 뿐이다. 세션은 ios, androids, browser 모두 사용가능하지만 쿠키는 only 브라우저에서만 사용할 수 있다. 

그래서 토큰을 사용한다. 서버에 '토큰'을 보냄.

세션은 현재 로그인한 유저들의 모든 세션ID를 DB에 저장해야한다.request가 있을때마다 쿠키와함께 세션ID로 DB에 일치하는 유저를 찾아야함.(유저가 많아질수록 DB리소스가 더 필요해짐)

 

세션: 세션ID만 줌(세션에 대한 정보는 세션DB에 저장되어있다.)

         페이지를 요청하면 서버는 세션 ID를 DB에서  찾음.

         새로운 기능을 추가할 때

ex)로그아웃 -> 세션 delete

인스타 로그인 디바이스 강제 삭제로 로그아웃 

넷플이나 딪플처럼 계정 공유 인원을 제한할 수도 있다. 주로 redis(빠르고 저렴함)사용

->> 유저가 늘어날 수록 DB 사용 유지 비용이 커짐

 

-> 이때, JWT 토큰을 사용한다. 

 

** JWT = Jason Web Token

(base64로 인코딩을한다.)

header -> 서명 방법

ex) {

        "alg*":"*HS256";

        "typ*":"*JWT"

}

claim (payload 속 각 부분) 

payload (내용)

signature (서명)-> HMAC 대칭키를 사용한 단방향 암호화 사용 

 

 

세션DB를 갖고있을 필요는없다. 또 서버가 인증 요청을 하기위해 바쁘게 움직일 필요도 없다.

쿠키는 공간의 제약이 있지만 JWT는 제약이 없어서 엄청 길어도 됨.

DB를 건드리지 않고 정보를 사인하고 전달함.

서버에 request,세션 ID와 비슷하게 사인된 정보/토큰을 서버에 보내야함.

서버는 토큰을 받으면 해당 사인이 유효한지 체크한 뒤, 유저로 인증함.

 

 

JWT : 서버가 유저를 인증하는 데에 필요한 정보를 토큰에 저장, 토큰 자체를 브라우저로 보낸다.

페이지 요청 시, 서버는 해당 토큰이 유효한지만 "검증" 하면 끝(로그인 할 때 한번만 확인하고 매번 DB를 거치지 않아서 세션DB사용 안함)

Single Sign-On, 인증, 권한

 

**JWT는 암호화되어있지않아서 누구나 볼 수 있다는 단점이 있다. 

--> 강제 로그아웃을 할 수 없다! 서비스가 커지고 유저 계정 관리를 더 섬세하게 하고싶다면 세션으로 바꾸는 것이 나음.

 

JWT 로그아웃하는 방법: DB에 토큰 유효성을 서비스에서 부터 true false로 상태 바꾸면서 로그아웃 시킴.

 

 

 

[JWT를 세션대신 쓰는 이유 ]

-서버는 하나의 인스턴트로만 동작하지 않는다. 병렬서버(고가용성)로 운영하게 됨.

서버가 병렬로 운영되는 상황에서 세션을 사용하면, 각 서버간의 세션을 동기화하는 문제 발생(서버가 많아지면 세션동기는 더 어려워짐)

JWT를 사용하면 세션사용으로 인한 서버 부담도 줄면서 공유 세션에 대한 관리가 쉬워짐.

 

  • 서버 부하 감소:  서버가 인증 세션을 관리할 필요가 없기 때문에 서버의 부하가 줄어든다.
  • 확장성: 분산 시스템이나 로드 밸런싱 환경에서도 유용하다. 세션 기반 인증에서는 클라이언트가 매번 같은 서버에 요청을 보내야 하지만, JWT 기반에서는 어느 서버든 동일한 JWT를 검증할 수 있음
  • 단일 진입점: API Gateway나 마이크로서비스 아키텍처에서, JWT는 각 서비스에 대한 인증을 관리할 필요 없이 단일 진입점에서 검증될 수 있음

세션기반 인증은세션 동기화 문제가 발생할 수 있음

 

 

 

token 테이블을 따로 만들어서 관리하기도 한다.

**

Refresh Token

jwt를 시크릿 키의 유효기간은 refresh-Token보다 짧게 주는게 일반적이다.

 

블록체인 및 암호화 관련 기초 수업을 들었던 적이 있는데, 이럴 때 쓰인다고 한다.

해쉬코드 어쩌구 이야기한것도 기억이 나긴한다

보안 쪽은 개발자 중에서도 최최최상위라고 생각하는데

 딥하게 들어가면 엄청 어려운 분야같다..하하

 


< 내 코드 설명>

package lm.swith.user.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.web.filter.CorsFilter;

import lm.swith.user.token.JwtAuthenticationFilter;
import lombok.extern.slf4j.Slf4j;


	@EnableWebSecurity
	@Slf4j
	@Configuration
	public class WebSecurityConfig{
		
		@Autowired
		private JwtAuthenticationFilter jwtAuthenticationFilter;
		
		@Bean
	    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		 

	        http
	        
	        .cors(cors -> cors.disable())
	        .csrf(csrf -> csrf.disable()) 
	        .httpBasic(httpHasic -> httpHasic.disable()) // token을 사용하르모 basic 인증 disable
	        .sessionManagement((session) -> session // session 기반이 아님을 선언
	                .sessionCreationPolicy(SessionCreationPolicy.STATELESS))

	        .authorizeHttpRequests(authorizeRequests -> 
	        authorizeRequests
	            .requestMatchers(new AntPathRequestMatcher("/**")).permitAll()
	    )
	            .addFilterAfter(
	        			jwtAuthenticationFilter,
	        			CorsFilter.class);
	            
	            
	        	
	             // Disable CSRF protection


	        return http.build();
	    }
		
		@Bean
		static PasswordEncoder passwordEncoder() {
			return new BCryptPasswordEncoder(); 
            // 기본형식인 Security는 기본적으로 DelegatingPasswordEncoder를 BCryptPasswordEncoder() 형식으로 저장
		}
}

JWT를 사용한 인증세션 없는(stateless) 보안 설정

 

  • JwtAuthenticationFilter는 클라이언트가 요청에 포함한 JWT 토큰을 해석하고, 유효한 경우 해당 사용자를 인증
  • Spring Security는 세션을 사용하지 않고 JWT로 요청을 인증하며, 이를 통해 무상태(stateless) 방식의 인증이 가능
  • 비밀번호는 BCrypt 알고리즘을 사용해 안전하게 인코딩됨.

 

@EnableWebSecurity : Spring Security 설정을 활성화하는 어노테이션

 

@Slf4j : 로깅을 위한 어노테이션으로, lombok 라이브러리를 사용

 

@Configuration : Spring 설정 클래스임을 나타냄. Bean 정의나 설정이 들어갈 때 사용

 

JwtAuthenticationFilter : JWT 토큰을 검증하는 필터

 

cors(cors -> cors.disable()): CORS(Cross-Origin Resource Sharing)를 비활성화, 보안 정책에 따라 외부 도메인에서의 리소스 접근을 허용하지 않겠다는 의미

 

csrf(csrf -> csrf.disable()): CSRF(Cross-Site Request Forgery) 보호를 비활성화, JWT 기반 인증에서는 CSRF 토큰을 사용할 필요가 없기 때문에 이를 비활성화함

 

httpBasic(httpHasic -> httpHasic.disable()): Basic 인증을 비활성화 Basic 인증은 사용자의 ID와 비밀번호를 인코딩한 형태로 HTTP 요청 헤더에 포함시키지만, JWT 기반 인증을 사용하기 때문에 Basic 인증이 필요하지 않음

 

sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) :세션 관리를 **무상태(stateless)**로 설정합니다. JWT 토큰을 사용하는 경우 서버는 세션을 유지할 필요가 없으므로, SessionCreationPolicy.STATELESS를 사용하여 세션을 아예 생성하지 않도록 합니다.

 

authorizeHttpRequests : 특정 URL 패턴에 대해 접근 권한을 설정.

**requestMatchers(new AntPathRequestMatcher("/**")).permitAll()**로 모든 URL에 대해 접근을 허용, 이 설정은 변경하여 인증이 필요한 URL을 특정할 수 있음

 

addFilterAfter(jwtAuthenticationFilter, CorsFilter.class) : JWT 인증 필터(jwtAuthenticationFilter)를 CorsFilter 이후에 추가 이 필터는 각 요청의 JWT 토큰을 검증하고, 유효한 경우 해당 사용자를 인증된 사용자로 처리

 

비밀번호 인코딩 방식으로 BCryptPasswordEncoder를 사용

 

 

 

개념 출처 : 

https://youtu.be/tosLBcAX1vk?si=cP8avUR7tNFcxvAd 

https://youtu.be/MPXoTJ4-NuA?si=KzdBcxbVwNlD0SUA

https://youtu.be/36lpDzQzVXs?si=67nGHazhrjXuV2q8