종우의 컴퓨터 공간
스프링 시큐리티(Spring Security)와 OAuth 2.0으로 로그인 기능 구현 본문
<SecurityConfig 클래스>
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {...}
- SecurityConfig 클래스는 접근 권한을 작성하는 클래스이다.
- @EnableWebSecurity 어노테이션은 Spring Security 설정들을 활성화시켜 준다.
- WebSecurityConfigurerAdapter를 상속받은 config 클래스에 @EnableWebSecurity 어노테이션을 달면SpringSecurityFilterChain이 자동으로 포함된다. 그래서 configure(HttpSecurity http) 메소드를 오버라이드하여 스프링 시큐리티 규칙을 작성할 수있다.
.csrf().disable()
- Spring Security에서는 Cross Site Request Forgery(CSRF) 방지 장치가 기본으로 탑재되어 있다.
- 하지만 h2-console의 로그인 화면에서는 CSRF 처리가 되어있지 않으므로 면제 처리를 하지 않으면 에러가 발생한다.
- 여기서는 h2-console 화면을 사용하기 위해 해당 protection을 disable 한다.
- .csrf().ignoringAnMatchers("/h2-console/**")을 대신 사용함으로써 h2-console에 대해서만 면제 처리를 하면 더 좋다.
HomoEfficio/dev-tips
개발하다 마주쳤던 작은 문제들과 해결 방법 정리. Contribute to HomoEfficio/dev-tips development by creating an account on GitHub.
github.com
.headers().frameOptions().disable
- Spring Security는 기본적으로 X-Frame-Options 응답해더를 DENY로 설정한다.
- 그 말은 <frame> 이나 <iframe> 테그로 페이지를 표현하는 부분은 보여질 수 없음을 의미한다.
- 이렇게 설정되어 있는 이유는 사이트를 Clickjacking 공격으로부터 보호하기 위함이다.
- 따라서 h2-console을 사용하기 위해서는(<frame> tag를 사용하기에 조정해야한다.) 이 설정을 disable 해야한다.
- 하지만 이럴 경우 Clickjacking 공격으로 부터 보호받지 못하기 때문에, disable() 대신에 sameOrigin() 사용을 권장한다.
- .headers().frameOptions().sameOrigin()
- 참조: https://stackoverflow.com/questions/65894268/how-does-headers-frameoptions-disable-work
How does .headers().frameOptions().disable() work?
About Spring Security to let, control and get access to the h2 web console I read these two posts: Spring Boot /h2-console throws 403 with Spring Security 1.5.2 H2 console and Spring Security -
stackoverflow.com
.authorizeRequrests()
- URL 별 권한 관리를 설정하는 옵션의 시작점이다.
- authorizeRequests가 선언되어야만 anMatchers 옵션을 사용 할 수 있다.
.anMatchers()
- 권한 관리 대상을 지정하는 옵션이다.
- URL, HTTP 메소드별로 관리가 가능하다.
- "/" 등 지정된 URL들은 .permitAll() 옵션을 통해 전체 열람 권한을 줄 수 있다.
- POST 메소드이면서 "/api/v1/**" 주소를 가진 API는 .hasRole() 옵션을 통해 USER 권한을 가진 사람만 가능할 수 있다.
.anyRequest()
- 설정된 값들 이외의 나머지 URL들을 나타낸다.
- .authenticated()를 추가하여 나머지 URL들은 모두 인증된 사용자들에게만 허용하게 한다.
- 인증된 사용자, 즉 로그인한 사용자들을 이야기한다.
.logout().logoutSuccessfulUrl("/")
- 로그아웃 기능에 대한 여러 설정의 진입점이다. (.logout())
- 로그아웃 성공시 / 주소로 이동한다. (.logoutSuccessfulUrl("/"))
.oauth2Login()
- OAuth2 로그인 기능에 대한 여러 설정의 진입점이다.
.userInfoEndpoint()
- OAuth2 로그인 성공 이후 사용자 정보를 가져올 때의 설정들을 담당한다.
.userService()
- 소셜 로그인 성공 시 후속 조치를 진행할 UserService 인터페이스의 구현체를 등록한다.
- 리소스 서버(즉, 소셜 서비스들)에서 사용자 정보를 가져온 상태에서 추가로 진행하고자 하는 기능을 명시할 수 있다.
</SecurityConfig 클래스>
<CustomOAuth2UserService 클래스>
@Service
public class CustomOAuth2UserService implements OAuth2UserService<OAuth2UserRequest, OAuth2User> {...}
- 이 클래스에서는 구글 로그인 이후 가져온 사용자의 정보(email, name, picture, 등)들을 기반으로 추가로 진행하고자 하는 기능(가입 및 정보수정, 세션 저장, 등)을 지원한다.
- SecurityConfig 클래스에서 마지막에 .userService(<UserService 구현체>)에 들어갈 구현체를 만드는 클래스이다.
- @Service 어노테이션은 이 클래스가 서비스 클래스임을 명시한다.
- OAuth2UserService<OAuth2UserRequest, OAuth2User>을 implements 해서 loadUser() 메소드를 오버라이드한다.
참조 링크에는 처음에 받아온 userRequest와 DefaultOAuth2UserService()에 loadUser에 userRequest를 넘겨줬을 때, 받아오는 oAuth2User에 각각 어떤 정보들이 들어있는지 나와있다.
참조: https://robin00q.tistory.com/10
OAuth2.0 구글 아이디로 로그인 조금 더 알아보기
스프링 시큐리티와 OAuth2.0으로 로그인 기능 구현 스프링 시큐리티와 OAuth 2.0으로 로그인 기능 구현 스프링 시큐리티(Spring Security)는 막강한 인증과 인과(혹인 권한 부여) 기능을 가진 프레임워크
robin00q.tistory.com
HttpSession에 대한 개념은 새로운 포스팅에 설명해놨다.
참조: https://jwlim94.tistory.com/16
Session Management
jwlim94.tistory.com
</CustomOAuth2UserService 클래스>
<기존 테스트에 스프링 시큐리티 적용하기>
@WithMockUser(roles="USER")
- 인증된 모의(가짜) 사용자를 만들어서 사용한다.
- roles에 권한을 추가할 수 있다.
- 즉, 이 어노테이션으로 인해 ROLE_USER 권한을 가진 사용자가 API를 요청하는 것과 동일한 효과를 가지게 된다.
- MockMvc에서만 작동한다.
@Test
@WithMockUser(roles="USER")
public void savePosts() throws Exception {
....
}
@SpringBootTest에서 MockMvc를 사용하는 방법
- 아래와 같은 셋업이 필요하다.
@Autowired
private WebApplicationContext context;
private MockMvc mvc;
@Before
public void setup() {
mvc = MockMvcBuilders
.webAppContextSetup(context)
.apply(springSecurity())
.build();
}
- 아래와 같이 테스트를 진행한다. (->mvc.perform())
//when
mvc.perform(post(url)
.contentType(MediaType.APPLICATION_JSON_UTF8)
.content(new ObjectMapper().writeValueAsString(requestDto)))
.andExpect(status().isOk());
//then
List<Posts> posts = postsRepository.findAll();
assertThat(posts.get(0).getTitle()).isEqualTo(title);
assertThat(posts.get(0).getContent()).isEqualTo(content);
</기존 테스트에 스프링 시큐리티 적용하기>
'스프링 부트 (SpringBoot)' 카테고리의 다른 글
커스텀 어노테이션(Custom Annotation) 만들기 (0) | 2021.07.17 |
---|---|
세션 관리(Session Management) (0) | 2021.07.16 |
Optional in Java (0) | 2021.07.15 |
Stream in Java (0) | 2021.07.14 |
Querydsl 개념과 신텍스 (0) | 2021.07.14 |