게시판 구현(4.0) - 로그인, 회원가입: spring Security 기본 설정 및 설명

김지민·2023년 6월 30일

spring Boot

목록 보기
7/9

spring Security 설명 문서

  • 버전 고를 떄, snapshot: 테스트 중, GA: 테스트 완료 표현.

build.gradle에 spring Security 라이브러리 추가.


-> Add starter: dependency 추가 메뉴


-> 기존에 선택했던 것들: 다 체크해야 함.
-> 안 하면 다 지워짐.

next 누르고, 수정된 코드를 로컬로 복사. 이 뗴, maven-central에서 추가한
// Thymeleaf Layout Dialect 기능 사용:
implementation 'nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect:3.2.1'
이 사라지니 추가하기.

결과

그 후에,

하기, gradel을 새로 만든거이기에 종료+시작.

로그 변화

-> 비번 복사하기

다시 실행했을 경우 main에 다음과 같은 화면이 나옴. 또한, 주소창에 입력을 해도 무조건 다음 창으로 redirect됨.

아이디: user
비번: 복사한 것.

권장:
크롬 시크릿 창으로 열기 -> 로그 아웃 안되게

spring security 환경설정

  • @을 사용하여 자바 클래스 설정 또는 application.properties에서 설정.

SecurityConfig class

package com.itwill.spring4.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;

@EnableWebSecurity
// 스프링 컨테이너(프레임 워크)에서 빈(bean-객체)으로 생성, 관리 - 필요한 곳에 의존성 주입.
// 환경설정.
@Configuration
public class SecurityConfig {

    // Spring Security 5버전부터 비밀번호는 반드시 암호화를 해야 함.
    // 비밀번호를 암호화하지 않으면 HTTP 403(access denied, 접근 거부) 또는 
    // HTTP 500(internal server error, 내부 서버 오류)가 발생함.
    //-> (웹 서비스에서 사용하는) 비밀번호 인코더(Password encoder) 객체를 bean으로 생성해야 함.
    
    /**
     * BCryptPasswordEncoder: 
     * 비밀번호를 다른 문자열로 리턴.
     * 암호화가 필요한 곳에 사용
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder(); // 인터페이스는 기본생성자로 안되니 'The preferred implementation is BCryptPasswordEncoder.' 를 참고하여 함.
    }

    // 로그인할 때 사용할 임시 사용자(메모리에 임시 저장) 생성
    // 다음을 생성시 임시로 알려준 spring 비번을 알려주지 않음
    // spring security filter/dipatcher Service는 UserDetailsService을 찾고 사용자 상세정보를 만들어줌
    // 그래서 해당 클래스를 상속받아야 그대로 동작이 가능함.
    // UserDetailsService: 로그인 필터가 사용자 정보를 가져오고자 하는 클래스. 
    // -> 클래스 에서 UserDetailsService를 구현해야 로그인 필터가 사용자 정보를 가지고 올 수 있음.
    // -> 또한, UserDetailsService에는 userDetails 정보가 꼭!! 필요함.
    @Bean
    public UserDetailsService  inMemoryUserDetailsServic() {
        // repository가 됨. 임시로 생성한 일종의 Entity가 됨
        // 사용자 상세 정보.
        UserDetails user1 = User
                    .withUsername("user1") // 로그인할 떄 사용할 사용자 이름
                    .password(passwordEncoder().encode("1111")) // 로그인할 때 사용할 비밀번호
                    .roles("USER") // 사용자 권한(USER, ADMIN,.... -> 사용자에 따라 페이지 구분 가능함.)
                    .build(); //UserDetails 객체 생성.
        
        UserDetails user2 = User
                .withUsername("user2") 
                .password(passwordEncoder().encode("2222")) 
                .roles("USER", "ADMIN") 
                .build(); 
        
        UserDetails user3 = User
                .withUsername("user3") 
                .password(passwordEncoder().encode("3333")) 
                .roles("ADMIN") 
                .build(); 
        
        return new InMemoryUserDetailsManager(user1, user2, user3);
    } 
    
    
    // 찐 환경설정.
    // Security Filter 설정 Bean 
    // -> Security Filter: 로그인관련된 인증 필터
    // (예) 로그인/로그아웃 설정, 로그인 페이지 설정, 페이지 접근 권한 - 로그인 해야만 접근 가능한 페이지, 로그인 없이 접근 가능한 페이지.
    // 다음 SecurityFilterChain설정을 했기에 로그인없이 들어가짐.(~86까지 만듦) -> 페이지 권한 설정을 안 했기에, 
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        
        // CSRF(Cross Site Request Forgery) 기능 활성화하면,
        //-> 보안은 좋음 단, Ajax POST/PUT/DELETE 요청에서 CSRF 토큰을 서버로 전송하지 않으면 403(접근 거부) 에러가 발생
        //-> CSRF 기능 비활성화.
        http.csrf((csrf)-> csrf.disable());
        
        // 로그아웃 이후 이동할 페이지
        //-> 메인 페이지로 이동.
        http.logout((logout) -> logout.logoutSuccessUrl("/") );
        
        // 로그인 페이지 설정 - withDefaults: 스피링에서 제공하는 기본 로그인 페이지를 사용.
        // -> 개인 설정 로그인 페이지 사용시 Customizer.다음을 설정하면 됨
        http.formLogin(Customizer.withDefaults());
        
        // 페이지 접근 권한 설정 -> 순서 중요
        http.authorizeHttpRequests((authRequest) -> 
                            authRequest // 접근 권한을 설정할 수 있는 객체
                            // 권한이 필요한 페이지들을 설정
                            .requestMatchers("/post/create", "/post/details", "/post/modify", "/post/update", "/post/delete"
                                    ,"/api/reply/**") // 다음 페이지는 + 쿼리 스프링 따로 표현 안 해도 됨.
                            .hasRole("USER") // 위에서 설정한 페이지들이 USER 권한을 요구함을 설정.
                            .anyRequest() // .requestMatchers("/**") -> 위 페이지들 이외의 모든 페이지
                                          // (/post/details) -> **: 하위 주소(/details)가 몇 단계가 와도 상관없음
                            .permitAll()); // 권한없이 접근 허용
        
        return http.build();
    }

}

만약, USER 권한으로 설정한 페이지들에 ADMIN 권한을 가진 유저가 접근할 경우 다음과 같은 에러가 뜸



==> 권한 없음.

+ .authenticated()

-> 권한 여부에 상관없이 아이디/ 비번이 일치하면 페이지 설정.

http.formLogin: 문서 상세히 보기 사용 방법 예제 존재

요청주소가 많을 경우 설정.

단점: 새로운 요청 경로, 컨트롤러를 작성할 때마다 Config 자바 코드를 수정해야 함.
-> 컨트롤러 메서드를 작성할 때 에너테이션을 사용해서 접근 권한을 설정할 수 있도 있음.
(1) SecurityConfig 클래스에서 @EnableMethodSecurity 에너테이션 설정 -> controller 메서드에서 security 설정.
(2) 각각의 컨트롤러 메서드에서 @PreAuthorize 또는 @PostAuthorize(메서드 끝난 다음에 인증 -> 드묾) 애너테이션을 사용.

스프링 컨테이너 추가 설명

spring Application이 컨테이너 관리

-> 필요한 곳에 의존성 주입을 함.

상속관계
@Bean
|__@component
|__ @reposityory, @controller, @service, @configuration

의의: @Bean들을 관리하는 무엇/ 객체들을 관리하는 무엇 -> 객체 생성.
역할: 객체 생성,관리,주입 역할

+ tomcat == servlet container

profile
한 단계씩 차근차근

0개의 댓글