묻고 답해요
137만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결스프링 시큐리티 완전 정복 [6.x 개정판]
실무에서 spring boot 2.6.x 버전을 사용 하고 있는데요.
여기서 강의 나오는 버전 경우 spring security 버전이 6.x 버전입니다. 현재 실무에서 사용하고 있는 spring boot 버전이 2.6.x 인데요. boot 업그레이드 하지 않고 security 버전을 6.x 버전으로 올려도 괜찮을까요?... implementation group: 'org.springframework.boot', name: 'spring-boot-starter-security', version: '3.2.5' build.gradle 파일에 이렇게 수정해서 올렸더니 @EnableWebSecurity같은 중요한 객체가 import가 안되는 문제가 생겨서요 ㅠㅠ
-
해결됨스프링 시큐리티 완전 정복 [6.x 개정판]
AuthenticationManager 사용방법에 대해 질문있습니다.
안녕하세요 강의 잘 보고 있습니다.다름이 아니라 강의를 보며 궁금한 점이 생겨 이렇게 질문드립니다.영상및 강의자료에서는 Authentication Manager를 사용할때 CustomFilter를 다루는 부분이 나옵니다. 이때 첫번째 방법(HttpSecurity 사용)은 필터를 Bean으로 등록하는 것이 아닌 직접 필터 객체를 생성하고 Authentication ManagerBuilder를 통해 직접 build한 Authentication Manager에 등록하고 두번째 방법(직접 생성)은 필터를 빈으로 등록하고 Authentication Manager관련 프로세스는 스프링 시큐리티에 위임한다는 느낌을 받았습니다. 이때 이 두가지 방법의 차이는 어떤 것이 있을까요? Authenticaion Manager를 직접 생성하기에 세밀한 설정이 가능하다는 차이가 있고 없고인가요?스프링 시큐리티의 버전이 변경되면서 필터를 Bean으로 등록해 사용하도록 권장하고 있다고 알고 있습니다. 이러한 관점에서 보았을때는 두번째 방법이 스프링 시큐리티 측에서 권장하는 방법으로 이해해도 될까요?
-
해결됨스프링 시큐리티 완전 정복 [6.x 개정판]
PPT 강의 자료는 어디 있을까요...?
안녕하세요 선생님~! 혹시 PPT 강의 자료는 어디 있을까요...? ㅠㅠ
-
미해결스프링 시큐리티 완전 정복 [6.x 개정판]
react 와 같은 별개의 프론트가 있는 경우 csrf
이런 경우에는 rest 방식으로 로그인할때, csrf 값을 처리할 수 없을거 같은데요. same-site 방식으로 처리하면 되는걸까요?
-
미해결스프링 시큐리티 완전 정복 [6.x 개정판]
강의 교안에서 SessionManagementFilter 이미지 질문
강의 교안의 동시 세션제어필터 로직의 흐름도 그림에서SessionManagementFilter가 세션 만료 설정 플래그를 설정하는 그림에서 혼동이 있어서 질문드립니다. 현재 스프링시큐리티 6 이후 기본동작에서는 SessionManagementFilter가 기본 동작하지 않는 것으로 알고 있습니다. 실제로 세션 관련 설정을 이것저것 바꿔봐도 SessionManagementFilter가 필터체인에 추가되지 않더군요.(실제로 강의에서도 이 부분을 언급하신 것을 확인했고, 공식문서에서도 확인했습니다.)대신 UsernamePasswordAuthenticationFilter(정확히는 이것의 상위 클래스인 AbstractAuthenticationProcessingFilter)와 같은 곳에서 명시적으로 sessionAuthenticationStrategy를 호출하여 세션 관련 처리를 위임시키는 식으로 처리하는데요.현시점 기본 동작 관점에서 보면 강의 교안에 나와있는 흐름도를 보면 SessionManagementFilter로 그림이 나와잇는 부분은 UsernamePasswordAuthenticationFilter와 같은 최초 로그인을 담당하는 필터에서 인증후 strategy를 통해 만료플래그가 설정되는 것으로 나타나게 하는 것이 좀 더 정확하지 않을까 싶어서 질문을 드립니다.
-
해결됨스프링 시큐리티 완전 정복 [6.x 개정판]
http 파일이 잘 안 먹힐 때
### 로그인 POST http://localhost:8080/login Content-Type: application/json { "username": "user", "password": "1111" } > {% client.global.set("JSESSIONID", response.headers.valueOf("Set-Cookie").split(";")[0].split("=")[1]) %} ### 루트 접속 GET http://localhost:8080/ Accept: application/json Cookie: JSESSIONID={{JSESSIONID}}강의에서 설명하신 대로 따라해봤는데 http 파일이 잘 작동하지 않는 문제가 있었습니다.이 부분이 잘 안 먹혀서 찾아봤는데 인프런 현재 CTO이신 '향로'님 블로그쪽에 이 내용이 정리가 되어 있는 것을 확인할 수 있었습니다.- https://jojoldu.tistory.com/366> {% %} 를 http 파일에 작성하고, 이 사이에서 응답이 온 데이터를 전역변수로 저장해둘 수 있습니다.이후 로그인할 때 Cookie: JSESSIONID={{JSESSIONID}} 와 같이 전역변수에서 꺼내서 사용하면 명시적으로 쿠키를 지정해서 전달할 수 있어서 작동이 잘 됩니다.
-
미해결스프링 시큐리티 완전 정복 [6.x 개정판]
405에러가 발생합니다. 이유를 잘 모르겠습니다.
1package com.attendance.scheduler.infra.config.security; import lombok.RequiredArgsConstructor; 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.annotation.web.configurers.AbstractHttpConfigurer; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.SecurityFilterChain; @Configuration @RequiredArgsConstructor @EnableWebSecurity public class SecurityConfig { public static final String[] ENDPOINTS_WHITELIST = { "/", "/submit", "/completion", "/class/**", "/board/**", "/join/**", "/cert/**", "/help/**", "/comment/**", "/css/**", "/js/**" }; private final CustomAuthenticationFailureHandler customAuthenticationFailureHandler; @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Bean public SecurityFilterChain adminFilterChain(HttpSecurity httpSecurity) throws Exception { httpSecurity .csrf(AbstractHttpConfigurer::disable) .securityMatcher("/admin/**","/manage/**") .authorizeHttpRequests(auth -> auth .requestMatchers("/admin/**") .hasAuthority("ADMIN") .requestMatchers("/manage/**") .hasAnyAuthority("ADMIN", "TEACHER") .anyRequest().authenticated()) .formLogin(httpSecurityFormLoginConfigurer -> httpSecurityFormLoginConfigurer .defaultSuccessUrl("/manage/class", true) .failureHandler(customAuthenticationFailureHandler) .loginPage("/login") .loginProcessingUrl("/login") ) .logout(httpSecurityFormLogoutConfigurer -> httpSecurityFormLogoutConfigurer .logoutUrl("/logout") .invalidateHttpSession(true) .deleteCookies("JSESSIONID") .logoutSuccessUrl("/")) .sessionManagement(sessionManagement -> sessionManagement .invalidSessionUrl("/login") .maximumSessions(1) .maxSessionsPreventsLogin(true) .expiredUrl("/login")); return httpSecurity.build(); } } 2package com.attendance.scheduler.infra.config.security; import com.attendance.scheduler.admin.domain.AdminEntity; import com.attendance.scheduler.admin.repository.AdminJpaRepository; import com.attendance.scheduler.infra.config.security.Admin.AdminDetails; import com.attendance.scheduler.infra.config.security.User.TeacherDetails; import com.attendance.scheduler.teacher.domain.TeacherEntity; import com.attendance.scheduler.teacher.repository.TeacherJpaRepository; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Component; @Slf4j @Component @RequiredArgsConstructor public class AccountDetailService implements UserDetailsService { private final AdminJpaRepository adminJpaRepository; private final TeacherJpaRepository teacherJpaRepository; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { log.info("teacherId = {}", username); final TeacherEntity teacherEntity = teacherJpaRepository .findByUsernameIs(username); if(teacherEntity != null){ return new TeacherDetails(teacherEntity); } else { final AdminEntity adminEntity = adminJpaRepository .findByUsernameIs(username); if (adminEntity != null) { log.info("adminId = {}", username); return new AdminDetails(adminEntity); } } throw new UsernameNotFoundException(username); } }3<form method='post' th:action="@{/login}" th:object="${login}"> 로그인을 진행하면 405에러가 계속 발생합니다. 이유를 찾고 있으나 아이디와 비밀번호를 입력해도 2번 코드의 로그에 남지 않습니다. 혹시 이유를 알려주실수 있을까요? 감사합니다.
-
미해결스프링 시큐리티 완전 정복 [6.x 개정판]
15섹션 프로그래밍 방식의 인가 구현 – DB 연동 / 여러개의 권한매핑
섹션 15 (프로그래밍 방식의 인가 구현 – DB 연동) 강의에서 6:10 에 작성하신 코드위 코드에 대해서 질문 드립니다. 저는 PageDto라는 객체를 만들고해당 객체는 String url, Set<PageRole>으로 구성되어있고위와 같이 코드를 작성하였습니다.데이터를 Map에 넣고 콘솔창에 출력해보았을 때url값이 중복이라(맵의 key값) 마지막 권한만이 Map<String, String>객체에 들어가는데 하나의 url에 여러 개의 권한을 매핑 할 때 해당 구조로 작성 하는 것이 맞는지 질문 드립니다.만약에 Map<String, Set>구조이면 이후 커스텀 매니저에서 setMapping()의 로직이 달라지는지도 궁금합니다.
-
미해결스프링 시큐리티 완전 정복 [6.x 개정판]
아직 강의를 끝까지 다 안들어서 그런데 JWT 구현 강의가 나중에 있나요?
아직 강의를 끝까지 다 안들어서 그런데 JWT 구현 강의가 나중에 있나요?
-
미해결스프링 시큐리티 완전 정복 [6.x 개정판]
13분 11초에서 최근 파일 보는 단축키
강사님 안녕하세요, 강의 잘듣고 있습니다. 디버깅하면서 내용을 이해하려고 하는데 따라가기가 조금 벅차네요. 13분 11초 대에 Recent files 검색하는 부분 윈도우 단축키가 무엇인지 궁금합니다. 좋은강의 감사합니다.
-
미해결스프링 시큐리티 완전 정복 [6.x 개정판]
Redis만 사용하면 인증 상태 영속이 되지 않습니다..!
안녕하세요 구버전에 이어 신버전 강의도 출시해주셔서 감사합니다! 구버전 커뮤니티에 질문올렸었는데요~이번 강의를 봐도 해결이 되지않아서 질문 올려봅니답..!직접 spring security 메인테이너나 컨트리뷰터들한테도 물어봤는데, 제가 제대로 질문을 못해서인지 해결을 못했는데요. 시큐리티 + formlogin + Redis를 활용해서 인증방식을 구현했습니다. 아래 코드로 인증 객체를 꺼낼때 문제가 발생합니다. @ResponseStatus(HttpStatus.OK) @GetMapping("/test") public void test() { SecurityContextHolderStrategy contextHolderStrategy = SecurityContextHolder.getContextHolderStrategy(); System.out.println(">> contextHolderStrategy : " + contextHolderStrategy); // org.springframework.security.core.context.ThreadLocalSecurityContextHolderStrategy@7e1fbf12 SecurityContext context = contextHolderStrategy.getContext(); System.out.println(">> context : " + context); // SecurityContextImpl [Authentication=AnonymousAuthenticationToken Authentication authentication = context.getAuthentication(); System.out.println(">> authentication : " + authentication); // AnonymousAuthenticationToken MemberContext memberContext = (MemberContext) authentication.getPrincipal(); System.out.println(">> memberContext : " + memberContext); // ClassCastException String username = memberContext.getUsername(); System.out.println(">> username : " + username); } Redis를 사용하지 않고 tomcat에 저장할 경우 session을 통해서 인증 객체를 잘 받아오는데,>> contextHolderStrategy : org.springframework.security.core.context.ThreadLocalSecurityContextHolderStrategy@54f61d2b >> context : SecurityContextImpl [Authentication=UsernamePasswordAuthenticationToken [Principal=com.spring.security.config.security.service.MemberContext [Username=sejinpark@email.com, Password=[PROTECTED], Enabled=true, AccountNonExpired=true, CredentialsNonExpired=true, AccountNonLocked=true, Granted Authorities=[ROLE_ADMIN]], Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=A220DB3D8904393F7D9831276564566A], Granted Authorities=[ROLE_ADMIN]]] >> authentication : UsernamePasswordAuthenticationToken [Principal=com.spring.security.config.security.service.MemberContext [Username=sejinpark@email.com, Password=[PROTECTED], Enabled=true, AccountNonExpired=true, CredentialsNonExpired=true, AccountNonLocked=true, Granted Authorities=[ROLE_ADMIN]], Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=A220DB3D8904393F7D9831276564566A], Granted Authorities=[ROLE_ADMIN]] >> memberContext : com.spring.security.config.security.service.MemberContext [Username=sejinpark@email.com, Password=[PROTECTED], Enabled=true, AccountNonExpired=true, CredentialsNonExpired=true, AccountNonLocked=true, Granted Authorities=[ROLE_ADMIN]] >> username : sejinpark@email.com Redis만 사용하면 인증 완료 후 인증 후 요청에서 Anonymous로 변경됩니다.>> contextHolderStrategy : org.springframework.security.core.context.ThreadLocalSecurityContextHolderStrategy@577154a7 >> context : SecurityContextImpl [Authentication=AnonymousAuthenticationToken [Principal=anonymousUser, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=16bec162-3ad3-459d-8b97-bf3d6f1de226], Granted Authorities=[ROLE_ANONYMOUS]]] >> authentication : AnonymousAuthenticationToken [Principal=anonymousUser, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=16bec162-3ad3-459d-8b97-bf3d6f1de226], Granted Authorities=[ROLE_ANONYMOUS]] 2024-04-17T07:49:13.061+09:00 ERROR 84540 --- [nio-8080-exec-6] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: java.lang.ClassCastException: class java.lang.String cannot be cast to class com.spring.security.config.security.service.MemberContext (java.lang.String is in module java.base of loader 'bootstrap'; com.spring.security.config.security.service.MemberContext is in unnamed module of loader 'app')] with root cause java.lang.ClassCastException: class java.lang.String cannot be cast to class com.spring.security.config.security.service.MemberContext (java.lang.String is in module java.base of loader 'bootstrap'; com.spring.security.config.security.service.MemberContext is in unnamed module of loader 'app') at com.spring.security.controller.MemberController.test(MemberController.java:43) ~[main/:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]Redis 내부에 인증객체가 저장되어 있는것 까지 확인했는데요. 혹시 SecurityFilterChain에 Redis관련 저장소를 별도로 설정을 해줘야 하는지, 어떤 부분을 확인해야하는지 여쭙고 싶습니다. Redis를 사용하는데 계속 HttpSessionSecurityContextRepository에서 시큐리티 컨텍스트를 찾을 수 없다고 나옵니답.2024-04-17T17:05:01.251+09:00 WARN 30066 --- [nio-8080-exec-1] w.c.HttpSessionSecurityContextRepository : SPRING_SECURITY_CONTEXT did not contain a SecurityContext but contained: '{authentication={authorities=[{authority=ROLE_ADMIN}], details={remoteAddress=0:0:0:0:0:0:0:1, sessionId=null}, authenticated=true, principal={password=null, username=sejinpark@email.com, authorities=[{authority=ROLE_ADMIN}], accountNonExpired=true, accountNonLocked=true, credentialsNonExpired=true, enabled=true}, credentials=null, name=sejinpark@email.com}}'; are you improperly modifying the HttpSession directly (you should always use SecurityContextHolder) or using the HttpSession attribute reserved for this class? 우선 테스트용으로 SecurityFilterChain에서 아래처럼 기존 버전 처럼 사용해서 인증 상태를 무조건 저장할 수 있도록 해놨습니다.커스텀 인증필터를 사용 안하고, SecurityContextPersistanceFilter를 사용하도록했습니다.securityContext.requireExplicitSave(false);테스트용으로 만든 레포지토리 링크 첨부합니다!https://github.com/codesejin/security-test
-
미해결스프링 시큐리티 완전 정복 [6.x 개정판]
hasRole 과 hasAuthority 의 차이
안녕하세요 hasRole 과 hasAuthority 의 차이가 없는 거 같아서 질문 드립니다.기능 상 차이가 없다면 용도의 차이가 있는지 궁금합니다.
-
해결됨스프링 시큐리티 완전 정복 [6.x 개정판]
Basic Authorization 헤더는 인증 후 모든 요청에 자동으로 설정되는 건가요?
안녕하세요 선생님, 질문이 있습니다.[ 기본 인증 필터 - BasicAuthenticationFilter ] - 14:00 ~ 14:20 부분에서 Http Request Header 에 Authroization Header 가 자동으로 세팅이 되는데, 이건 브라우저가 지원해주는 기능인 건가요??
-
해결됨스프링 시큐리티 완전 정복 [6.x 개정판]
REST 방식과 폼 인증 방식의 차이점과 언제 적용하는 질문입니다.
타임 리프로 페이지를 구성한다면 CSRF 토큰을 타임리프에서 자동으로 생성하기 때문에 직전 세션인 [실전 프로젝트 - 회원 인증 시스템] 강의 내용으로 스프링 시큐리티 설정이 충분하지만, 타임 리프가 아닌 자바스크립트 기반의 뷰나 리액트 등으로 페이지를 구성할 때에는 [실전 프로젝트 - 비동기 인증] 으로 스프링 시큐리티를 설정해야 되는 것으로 생각하면 될까요?그 이유는 CSRF 토큰을 자바스크립트에서는 자동으로 생성하지 않기 때문이다. 라고 이해했는데 다른 이유가 혹시 더 있을까요?
-
해결됨스프링 시큐리티 완전 정복 [6.x 개정판]
SecurityContextHolderStrategy 관련 질문
리멤버미 인증에서 doFilter 호출한 시점에서 securityConttextHolderStrategy는 요청-응답 흐름에서 SecurityContext를 어떻게 관리할 것인지 관리하는 전략인데 이것은 세션과 다르고 기본 구현체로 ThreadLocalSecurityContextHolderStrategy가 사용되어 개별 스레드 단위로 격리되어 SecurityContext가 관리되는 것으로 알고 있습니다.강의에서 이 부분을 세션에 저장되어있는지 확인하고 리멤버미 인증을 시작할 것인지 아닐 것인지 결정하는 것으로 말씀 주셨는데, 정확히는 앞에 있는 필터에서 인증을 거치고(기본적으로 세션 인증) 인증 결과를 SecurityContextHolderStrategy에 저장시킨 상태에서 인증이 됐는 지 여무를 확인하는 것을 축약해서 말씀해주신 것인지 혼동이 있어서 질문드립니다.
-
해결됨스프링 시큐리티 완전 정복 [6.x 개정판]
강의자료 오타 제보
UsernamePasswordAuthenticationFilter 설명부 이미지 GET /login 이 아니라 POST /login 같습니다!
-
해결됨스프링 시큐리티 완전 정복 [6.x 개정판]
Kotlin DSL 활용
import org.springframework.security.config.annotation.web.invoke시큐리티 5.3부터 Kotlin 환경에서 스프링 시큐리티를 사용하실 때 DSL을 지원받을 수 있습니다.공식문서에 나와있습니다.(https://docs.spring.io/spring-security/reference/servlet/configuration/kotlin.html)이 DSL을 사용한 예제 프로젝트도 제공됩니다. (https://github.com/spring-projects/spring-security-samples/tree/main/servlet/spring-boot/kotlin/hello-security) DSL 문 삽입은 IDE의 지원을 받을 수 없어서 위 import 문을 직접 작성해야합니다. @Configuration class SecurityConfig { @Bean fun securityFilterChain(http: HttpSecurity): SecurityFilterChain { http { authorizeHttpRequests { authorize("/", permitAll) authorize(anyRequest, authenticated) } formLogin {} rememberMe { } sessionManagement { sessionCreationPolicy = SessionCreationPolicy.STATELESS } } return http.build() } } 예를 들면 위와 같이 DSL의 지원을 받아 설정을 구성할 수 있습니다.람다 표현식을 작성하지 않고 설정할 수 있습니다.IDE를 통해 DSL 설정 클래스를 쭉 따라가보면 어떤 파라미터를 전달하면 될지 확인할 수 있는데 이를 참고하면 좀 더 편리하게 설정을 사용할 수 있습니다.다만 일부 설정은 제공되지 않는 것도 있어서 해당하는 부분은 Spring에서 제공되는 API 그대로 사용하셔야합니다.