인프런 영문 브랜드 로고
인프런 영문 브랜드 로고

인프런 커뮤니티 질문&답변

rnqhstlr2297님의 프로필 이미지
rnqhstlr2297

작성한 질문수

스프링부트 시큐리티 & JWT 강의

인증이나 권한이 필요한 요청

작성

·

298

0

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("인증이나 권한이 필요한 요청");

String jwtHeader = request.getHeader(JwtProperties.HEADER_STRING);
if(jwtHeader ==null || !jwtHeader.startsWith(JwtProperties.TOKEN_PREFIX)) {
/**
* 이거 필터로 걸려야 되는거 아니야?! 인증이나 권한이 없는거니깐
*/
chain.doFilter(request, response);
return;
}

System.out.println("jwtHeader:" + jwtHeader);
String token = request.getHeader(JwtProperties.HEADER_STRING).replace(JwtProperties.TOKEN_PREFIX, "");


String username = JWT.require(Algorithm.HMAC512(JwtProperties.SECRET)).build().verify(token)
.getClaim("username").asString();

if(username !=null) {
User user = userRepository.findByUsername(username);

// 인증은 토큰 검증시 끝.
// 인증을 하기 위해서가 아닌 스프링 시큐리티가 수행해주는 권한 처리를 위해
// 아래와 같이 토큰을 만들어서 Authentication 객체를 강제로 만들고 그걸 세션에 저장!
PrincipalDetails principalDetails = new PrincipalDetails(user);
Authentication authentication = new UsernamePasswordAuthenticationToken(
principalDetails, // 나중에 컨트롤러에서 DI해서 쓸 때 사용하기 편함.
null, // 패스워드는 모르니까 null 처리, 어차피 지금 인증하는게 아니니까!!
principalDetails.getAuthorities());

// 강제로 시큐리티의 세션에 접근하여 값 저장
SecurityContextHolder.getContext().setAuthentication(authentication);
}

chain.doFilter(request, response);
}

만약 "localhost:8080/home"으로 uri를 요청한다면 SecurityConfig에 해당 uri는 모두 허용이기 때문에 해당 스프링 시큐리티 필터를 타면 안되는것이 아닙니까??

그리고 탄다고 해서 인증권한이 요구되는 uri에서 해당 필터가 타게된다면 JWT토큰이 없으면 해당 인증이 안된다고 판단하여 다음 필터를 타지않고 reject를 해야하는것이 아닙니까? (if(jwtHeader==null ~ 부분에서))

그리고 마지막으로 궁금한점이 JWT 토큰을 가지고 인증 uri를 호출하면 사용자권한을 스프링 시큐리티를 통해서 편리하게 사용하기 위해서 강제로 Authentication객체를 생성하는데 해당 로직으로 한다면 JWT토큰이 올때마다 JWT토큰이 유효하다면 JWT토큰에서 username을 가지고 오는데 그럼 한 사용자가  인증이 필요한 uri로 올때마다 계속 Attentication객체를 생성해서 스프링 시큐리티에 저장하는것이 아닙니까?

읽어주셔서 감사합니당.!!

 

답변 3

0

최주호님의 프로필 이미지
최주호
지식공유자

우선 하나씩 하시죠 !!

 

 JWT의 이점인 세션영역을 사용하지 않는다는 장점!!

 

이 부분 부터!!

 

JWT를 사용하는 이점이 세션영역을 사용하지 않는다는 것은 아닙니다.

 

세션영역 자체가 나쁜 저장소가 아니기 때문입니다.

 

우선 세션영역을 사용하지 않으려는 이유는 서버의 수평적 확장이 있을 때 

세션 영역이 서버마다 생기기 때문에 .... 생기는 문제를 없애기 위해 세션영역을 안쓰려는 것입니다.

 

그런데 JWT를 사용하면서 서버가 확장되어도 인증이 가능해지고

잠깐 필요한 데이터만 세션영역에 저장해두고 쓰고 버리는 식으로 가면 좋은 점만 가져갈 수 있습니다.

 

우선 이부분 부터 명확히 생각해보세요

0

rnqhstlr2297님의 프로필 이미지
rnqhstlr2297
질문자

1. 인증이 필요한 uri요청이 올때마다 세션을 생성한다면 JWT의 이점인 세션영역을 사용하지 않는다는 장점이 없어지는것이 아닙니까? 단지 스프링 시큐리티를 통해서 권한체크를 편리하게 하기 위해서 세션영역을 계속 할당하고 생성하면 좋지 않은 방법이지 않습니까?!

2. 

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {


return http.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) //세션을 사용하지 않겠다!
.and()
.formLogin().disable()
.httpBasic().disable() //Bearer 방식 사용 -> header authentication 에 토큰을 넣어 전달하는 방식

.apply(new MyCustomDsl())
.and()

.authorizeRequests(authroize -> authroize
.antMatchers("/api/v1/user/**")
.hasAuthority("USER")
.antMatchers("/api/v1/manager/**")
.hasAuthority("MANAGER")
.antMatchers("/api/v1/admin/**")
.hasAuthority("ADMIN")
.anyRequest().permitAll())
.build();

}

.anyRequest().permiAll()로 인해서 위의 uri이 아닌 상황에서는 인증 권한체크를 하지 않는것이 아닙니까?

 

3.

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("인증이나 권한이 필요한 요청");

String jwtHeader = request.getHeader(JwtProperties.HEADER_STRING);
if(jwtHeader ==null || !jwtHeader.startsWith(JwtProperties.TOKEN_PREFIX)) {
/**
* 이거 필터로 걸려야 되는거 아니야?! 인증이나 권한이 없는거니깐
*/
chain.doFilter(request, response);
return;
}

System.out.println("jwtHeader:" + jwtHeader);
String token = request.getHeader(JwtProperties.HEADER_STRING).replace(JwtProperties.TOKEN_PREFIX, "");


String username = JWT.require(Algorithm.HMAC512(JwtProperties.SECRET)).build().verify(token)
.getClaim("username").asString();

if(username !=null) {
User user = userRepository.findByUsername(username);

// 인증은 토큰 검증시 끝.
// 인증을 하기 위해서가 아닌 스프링 시큐리티가 수행해주는 권한 처리를 위해
// 아래와 같이 토큰을 만들어서 Authentication 객체를 강제로 만들고 그걸 세션에 저장!
PrincipalDetails principalDetails = new PrincipalDetails(user);
Authentication authentication = new UsernamePasswordAuthenticationToken(
principalDetails, // 나중에 컨트롤러에서 DI해서 쓸 때 사용하기 편함.
null, // 패스워드는 모르니까 null 처리, 어차피 지금 인증하는게 아니니까!!
principalDetails.getAuthorities());

// 강제로 시큐리티의 세션에 접근하여 값 저장
SecurityContextHolder.getContext().setAuthentication(authentication);
}

chain.doFilter(request, response);
}

주석으로 표시해둔 부분에서  JWT토큰을 가지고 있는 사용자가 요청한 상황이니 필터를 통해서 컨트롤러등까지 호출하지 않게 처리해야되지 않습니까?  doFilter를 호출하지 않고

 

답변해주셔서 진심으로 감사드립니당!!

0

최주호님의 프로필 이미지
최주호
지식공유자

그리고 마지막으로 궁금한점이 JWT 토큰을 가지고 인증 uri를 호출하면 사용자권한을 스프링 시큐리티를 통해서 편리하게 사용하기 위해서 강제로 Authentication객체를 생성하는데 해당 로직으로 한다면 JWT토큰이 올때마다 JWT토큰이 유효하다면 JWT토큰에서 username을 가지고 오는데 그럼 한 사용자가  인증이 필요한 uri로 올때마다 계속 Attentication객체를 생성해서 스프링 시큐리티에 저장하는것이 아닙니까?

 

맞아요!! 요청할 때마다 세션에 보관합니다.

 

만약 "localhost:8080/home"으로 uri를 요청한다면 SecurityConfig에 해당 uri는 모두 허용이기 때문에 해당 스프링 시큐리티 필터를 타면 안되는것이 아닙니까??

 

이 부분은 코드를 봐야 알 것 같아요. 본인 코드를 github에 올리고 어느 파일을 봐야하는지 알려주세요.

 

그리고 탄다고 해서 인증권한이 요구되는 uri에서 해당 필터가 타게된다면 JWT토큰이 없으면 해당 인증이 안된다고 판단하여 다음 필터를 타지않고 reject를 해야하는것이 아닙니까? (if(jwtHeader==null ~ 부분에서))

 

위 답변과 동일합니다.

 

rnqhstlr2297님의 프로필 이미지
rnqhstlr2297

작성한 질문수

질문하기