본문 바로가기

SpringBoot

[Do it] 3장 스프링 부트 고급 기능 익히기(2)

1. 게시물에 번호 지정하기 

 

1) 게시물 번호 공식 만들기 

 

게시물 번호 = 전체 게시물 개수 - (현재 페이지 * 페이지당 게시물 개수) - 나열 인덱스 

 

게시물 번호

  - 최종 표시될 게시물 번호

 

전체 게시물 개수

- 데이터베이스에 저장된 게시물 전체 개수 

 

현재 페이지

- 페이징에서 현재 선택한 페이지 

 

페이지당 게시물 개수

- 한 페이지당 보여 줄 게시물의 개수 

 

나열 인덱스 

- for 문 안의 게시물 순서 

- 현재 페이지에서 표시할 수 있는 게시물의 인덱스 

- ex) 10개를 표시하는 페이지에서는 0~9, 2개를 표시하는 페이지에서는 0~1로 반복

 

 

2) 게시물 번호 공식 적용하기 

 

 

templates/question_list.html

 

항목 설명
paging.getTotalElements 전체 게시물 개수
paging.number 현재 페이지 번호
paiging.size 페이지당 게시물 개수 
loop.index 나열 인덱스 

 

 

2. 답변 개수 표시하기 

 

- 질문 목록 화면에서 해당 질문에 달린 답변 개수를 표시할 수 있는 기능 

 

templates/question_list.html

 

- th:if="${#lists.size(question.answerList)>0}"로 답변이 있는지 조사하고, th:text="${#lists.size(question.answerList)}"로 답변 개수를 표시 

 

 

3. 스프링 시큐리티란?

 

스프링 시큐리티(Spring Security)

- 스프링 기반 웹 애플리케이션의 인증과 권한을 담당하는 스프링의 하위 프레임워크 

 

- 인증(authenticate) 

  -> 로그인과 같은 사용자의 신원을 확인하는 프로세스 

 

- 권한(authorize)

  -> 인증된 사용자가 어떤 일을 할 수 있는지(어떤 접근 권한이 있는지)

 

 

1) 스프링 시큐리티 설치

 

build.gradle

 

2) 스프링 시큐리티 설정

 

 

- 스프링 시큐리티는 기본적으로 인증되지 않은 사용자가 웹 서비스를 사용할 수 없게끔 만듬

- 스프링 시큐리티 기본 기능을 그대로 적용할 수 없으니까 따로 설정 필요 

 

SecurityConfig.java

- 스프링 시큐리티의 설정을 담당

package com.example.demo;

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.web.SecurityFilterChain;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

@Configuration
@EnableWebSecurity
public class SecurityConfig {
	@Bean
	SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    	//인증되지 않은 모든 페이지의 요청을 허락
		http
		.authorizeHttpRequests((authorizeHttpRequests)->authorizeHttpRequests
				.requestMatchers(new AntPathRequestMatcher("/**")).permitAll());
		
		return http.build();
	}
}

 

@Configuration

 

- 이 파일이 스프링의 환경 설정 파일임을 의미 

- 스프링 시큐리티를 설정하기 위해 사용 

 

@EnableWebSecurity

 

- 모든 요청 URL이 스프링 시큐리티의 제어를 받도록 함

- 스프링 시큐리티를 활성화하는 역할 

- 내부적으로 SecurityFilterChain 클래스가 동작하여 모든 요청 URL에 이 클래스가 필터로 적용되어 URL별로 특별한 설정을 할 수 있게 함 

 

@Bean

 

- 스프링에 의해 생생 또는 관리되는 객체 

- 컨트롤러, 서비스 ,리포지터리 등도 모두 빈에 해당 

- 스프링 시큐리티의 세부 설정은 @Bean을 통해 SecurityFilterChain 빈을 생성하여 설정 가능 

 

 

3) H2 콘솔 오류 수정

 

- 스프링 시큐리티를 적용하면 H2 콘솔 로그인 시 403 Forbidden 오류가 발생 

 

403 Forbidden

- 작동 중인 서버에 클라이언트의 요청이 들어왔으나, 서버가 클라이언트의 접근을 거부했을 때 반환하는 HTTP 오류 코드 - 서버 또는 서버에 있는 파일 등에 접근 권한이 없을 경우에 발생

- 스프링 시큐리티의 CSRF 방어 기능에 의해 H2 콘솔 접근이 거부되기 때문

 

 

CSRF

- 웹 보안 공격 중 하나로, 조작된 정보로 웹 사이트가 실행되도록 속이는 공격 기술

- 스프링 시큐리티는 CSRF 토큰을 세션을 통해 발행하고, 웹 페이지에서는 폼 전송 시에 해당 토큰을 함께 전송하여 실제 웹 페이지에서 작성한 데이터가 전달되는지를 검증 

- 만약 CSRF 토큰이 없거나 해커가 임의의 CSRF 토큰을 강제로 만들어 전송한다면 스프링 시큐리티에 의해 차단 될 것

- H2 콘솔은 스프링 프레임워크가 아니므로 CSRF 토큰을 발행하는 기능이 없어 403 오류 발생 

 

SecurityConfig.java

- 스프링 시큐리티가 CSRF 처리 시 H2 콘솔은 예외로 처리 

...
@Configuration
@EnableWebSecurity
public class SecurityConfig {
	@Bean
	SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
		.authorizeHttpRequests((authorizeHttpRequests)->authorizeHttpRequests
				.requestMatchers(new AntPathRequestMatcher("/**")).permitAll())
		.csrf((csrf)->csrf
				.ignoringRequestMatchers(new AntPathRequestMatcher("/h2-console/**")));
 ...

 

- h2 콘솔 로그인은 수행되나 화면이 깨져 보임

 

- H2 콘솔의 화면이 프레임(frame) 구조로 작성되었기 때문

- H2 콘솔은 UI 레이아웃이 이 화면 처럼 작업 영역이 나눠져 있음을 의미 

 

- 스프링 시큐리티는 웹 사이트의 콘텐츠가 다른 사이트에 포함되지 않도록 하기 위해 X-Frame-Options 헤더의 기본값을 DENY로 사용하는데, 프레임 구조의 웹 사이트는 이 헤더의 값이 DENY인 경우 이와 같은 오류 발생 

 

X-Frame-Options 헤더

 

- 클랙재킹 공격을 막기 위해 사용 

- 클랙재킹 -> 사용자의 의도와 다른 작업이 수행되도록 속이는 보안 공격 기술 

 

SecurityConfig.java

@Configuration
@EnableWebSecurity
public class SecurityConfig {
	@Bean
	...
		.headers((headers)->headers
				.addHeaderWriter(new XFrameOptionsHeaderWriter(
						XFrameOptionsHeaderWriter.XFrameOptionsMode.SAMEORIGIN)));
						
		return http.build();
	}
}

 

- URL 요청 시 X-Frame-Options 헤더를 DENY 대신 SAMEORIGIN으로 설정하여 오류가 발생하지 않도록 함

- X-Frame-Options 헤더의 값으로 SAMEORIGIN을 설정하면 프레임에 포함된 웹 페이지가 동일한 사이트에서 제공할 때만 사용이 허락 됨