본문 바로가기

Study/개발일지

[백엔드온라인TIL] java 학습 21일차

Spring Security를 이용하기 위한 환경설정

build.gradle에 아래 디펜던시를 추가해주자.

	// spring security
	implementation 'org.springframework.boot:spring-boot-starter-security'
	implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5'
	testImplementation 'org.springframework.security:spring-security-test'

나는 따로 리액트나 뷰를 사용하지 않고 템플릿엔진인 Thymeleaf를 사용하기 때문에

thymeleaf-springsecurity 디펜던시를 추가해주었다.

 

또한, 테스트 코드에서 스프링 시큐리티 테스트를 진행할 수 있도록 spring-security-test 디펜던시를 추가해주었다.

 

application.properties는 아래와 같이 작성했다/

spring.datasource.username=[MySQL 아이디]
spring.datasource.url=jdbc:mysql://localhost:3306/[schema이름]?characterEncoding=UTF-8&serverTimezone=UTC
spring.datasource.password=[MySQL 비밀번호]

spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update

MySQL 기본 포트번호가 3306이다.

또한, ddl-auto = update로 진행할 경우엔, DB table에 변경사항이 생기는 코드 수정이 있을 때 바로바로 적용된다.

이 때의 변경사항이란, 새로운 데이터가 추가되는 이런게 아닌, 아예 테이블 하나가 새로 생성되거나, 테이블 연관관계가 바뀌거나 하는 것을 말한다.

 

Spring Security를 이용하기 위해선 Config를 설정해주어야 한다.

 

WebSecurityConfigureAdapter를 상속받는 SecurityConfig 클래스 코드를 만들어주자.

 

SecurityConfig.java

@EnableWebSecurity
@RequiredArgsConstructor
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private final MemberService memberService;

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/css/**", "/js/**", "/img/**");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                //.csrf().disable()// 나중에 없애기
                .authorizeRequests()
                .antMatchers("/", "/createMemberForm", "/login", "/errorPage", "/index").permitAll()
                .antMatchers("/editMember").hasRole("ADMIN")
                .anyRequest().authenticated()

                .and()
                .formLogin()
                .loginPage("/login")
                .defaultSuccessUrl("/")
                .permitAll()

                .and()
                .logout()
                .logoutSuccessUrl("/")
                .invalidateHttpSession(true)
                ;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(memberService)
                .passwordEncoder(new BCryptPasswordEncoder());
    }
}

@EnableWebSecurity 는 spring security를 사용가능하게 하는 어노테이션이다. 반드시 붙여주어야한다.

@RequiredArgsConstructor는 스프링 기본 어노테이션으로, final 필드변수들을 파라미터로 받는 생성자를 만들어준다.

여기서는 spring security 인증을 member에 관해서 진행하는 로그인 기능이기 때문에 MemberService를 받아준다.

@Configuration을 붙일 경우, 스프링 빈으로 등록된다.

 

이제 void configure 메소드를 설정해줄 차례인데, 오버로딩으로 인해 같은 메소드가 3개나 있는 것을 확인할 수 있다.

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/css/**", "/js/**", "/img/**");
    }

web을 띄울 때 인증이나 권한을 요구하지 않는 폴더(또는 파일)를 설정하는 것이다.

web.ignoring()으로 권한을 요구하지 않게 설정해주고, antMatchers로 path를 설정해줄 수 있다.

자세한 기능은 아래 블로그의 포스팅을 참고하자.

https://m.blog.naver.com/kimnx9006/220638156019

 

[스프링프레임워크] 스프링 시큐리티 -3. 요청 가로채기

요청 가로채기 각 요청에 대해서 보안 수준을 잘 조절하기 위한 키는 WebSecurityConfigurerAdapter의 ...

blog.naver.com

이어서 다음 configure 메소드를 보자.

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                //.csrf().disable()// 나중에 없애기
                .authorizeRequests()
                .antMatchers("/", "/createMemberForm", "/login", "/errorPage", "/index").permitAll()
                .antMatchers("/editMember").hasRole("ADMIN")
                .anyRequest().authenticated()
				
                //로그인
                .and()
                .formLogin()
                .loginPage("/login")
                .defaultSuccessUrl("/")
                .permitAll()
	
    			//로그아웃
                .and()
                .logout()
                .logoutSuccessUrl("/")
                .invalidateHttpSession(true)
                ;
    }

csrf는 보안 관련해서 스프링 시큐리티가 CSRF 공격을 방지해주기 위해 있는 것인데, 소규모 프로젝트에선 크게 문제없기도 하고, csrf().disable()를 해주지 않으면 적절한 처리가 있기 전엔 로그인 로직이 제대로 됨에도 불구하고 튕기기 때문에 이를 무시하는 csrf().disable() 코드를 작성해주어도 크게 문제는 없다. 다만, 보안에는 취약해지는 코드가 되는 것이다.

 

그러나 thymeleaf의 th:action을 사용하면 자동으로 csrf를 방지해주도록 한다고 한다. (자세히는 모르겠다...)

그래서 csrf().disable()을 해주지 않아도 로그인이 잘 된다는 말씀~

 

antMatchers에 해당하는 path들에게 

.permitAll() : 모든 유저의 접근 허용

.hasRole("ADMIN") : 관리자만 접근 허용

.anyRequest() : 그 외의 path들은

.authenticated : 인증된 (로그인된) 유저만 접근 허용

 

.and() : 또다른 http 설정을 할 때 사용한다. .and()를 붙이지 않고 http. 으로 진행해도 상관없다.

 

로그인페이지를 따로 설정해주지 않을경우(또는 그러한 html이 없을 경우) 스프링시큐리티에서  bootstrap css프레임워크로 아주 간단하게 만들은 기본적인 html창의 자체 로그인 html 화면을 자동으로 띄워준다.

 

로그인을 성공하면 defaultSuccessUrl로 설정된 path로 이동한다.

참고로 이 service 로직은 스프링 시큐리티 내에서 자체적으로 설정해주기 때문에, Service 코드에서 login 구현 코드를 따로 작성하지 않아도 좋다. (물론 추가적으로 기능을 추가하고 싶다면 오버라이딩 or 코드 추가하면 된다.)

 

로그아웃도 로그인과 마찬가지이다. 맨 마지막에 세션을 invalid화 시켜주는 것을 확인할 수 있다.

 

 

에러메시지 

 

2023-06-22T11:47:11.392+09:00  WARN 49440 --- [nio-8080-exec-1] o.s.s.c.bcrypt.BCryptPasswordEncoder     : Encoded password does not look like BCrypt

 

-> 추가로 bean으로 등록된 password 관련 클래스가 있는지 확인할것

728x90