Spring + Boot

Spring Security 연동하기 -1

devRachel 2021. 4. 15. 23:19

프로젝트 생성할 때 Spring Security 항목을 추가해서 생성해줍니다.

 

build.gradle에 다음과 같이 추가해주세요

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-security'
    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    compileOnly 'org.projectlombok:lombok'
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
    annotationProcessor 'org.projectlombok:lombok'
    providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
    testImplementation('org.springframework.boot:spring-boot-starter-test') {
        exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
    }
    testImplementation 'org.springframework.security:spring-security-test'

    compile group: 'org.mariadb.jdbc', name: 'mariadb-java-client'

    compile group: 'org.thymeleaf.extras', name: 'thymeleaf-extras-springsecurity5'
    compile group: 'org.thymeleaf.extras', name: 'thymeleaf-extras-java8time'

    compile group: 'org.thymeleaf.extras', name: 'thymeleaf-extras-springsecurity5'

    implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
    compile group: 'io.jsonwebtoken', name: 'jjwt', version: '0.9.1'
}

 

application.properties

spring.datasource.driver-class-name=org.mariadb.jdbc.Driver
spring.datasource.url=jdbc:mariadb://localhost:포트넘버/지정된이름
spring.datasource.username=아이디
spring.datasource.password=패스워드

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


spring.thymeleaf.cache=false


spring.servlet.multipart.enabled=true
spring.servlet.multipart.location=D:\\upload
spring.servlet.multipart.max-request-size=30MB
spring.servlet.multipart.max-file-size=10MB


logging.level.org.springframework.security.web = debug
logging.level.com.woman.security = debug

 

실행해보면 로그에 Using generated security password: 가 출력되는 것을 확인할 수 있습니다.

생성된 패스워드는 기본으로 사용할 수 있는 user 계정의 패스워드입니다. 프로젝트 생성 초기에 아무 계정도 없을 때 사용할 수 있는 임시 패스워드 역할을 합니다. 지금 바로 테스트를 하시면 컨트롤러가 없어서 에러 화면만 출력됩니다. 

이미 에러 페이지를 보신 경우.......  강제 로그아웃을 하고싶으시다면 개발자 도구에 있는 Application - Cookies 항목에 JSESSIONID 쿠키를 삭제 하시면 서버에서 사용할 수 없으므로 로그아웃 되며 새로운 계정으로 로그인 시도를 할 수 있습니다.

 

이제 시큐리티 설정 클래스를 만들어보겠습니다.

 

SecurityConfig 클래스는 시큐리티 관련 기능을 쉽게 설정하기 위해서 WebSecurityConfigurerAdapter라는 클래스를 상속으로 처리합니다. 주로 override를 통해서 여러 설정을 조정하게 됩니다.

 

import lombok.extern.log4j.Log4j2;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@Log4j2
public class SecurityConfig extends WebSecurityConfigurerAdapter {
}
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@Log4j2
@RequestMapping("/sample/")
public class SampleController {

    @GetMapping("/all")
    public void exAll(){
        log.info("전체허용페이지~~~~~~~~~~~~");
    }

    @GetMapping("/member")
    public void exMember(){
        log.info("회원전용입니다~~~~~~~~~");
    }

    @GetMapping("/admin")
    public void exAdmin(){
        log.info("관리자페이지입니다~~~~~~~~~~");
    }
}

 

 

스프링 시큐리티는 여러 개의 객체가 서로 데이터를 주고 받으면서 이루어집니다. 

 

Filter 1

Filter 2

Filter ... ------>Authentication Manager ------->AuthenticationProvider------>UserDetailsService

Filter N 

 

핵심 역할은 Authentication Manager(인증 매니저)를 통해서 이루어집니다.

Authentication Provider는 인증 매니저가 어떻게 동작해야 하는지를 결정하고 최종적으로 실제 인증은 UserDetailsService에 의해서 이루어집니다.

 

스프링 시큐리티를 관통하는 가장 핵심 개념은 인증(Authentication)과 인가(Authorization)입니다.

1. 사용자가 은행에 가서 자신이 어떤 사람인지 신분증으로 자신을 증명한다

2. 은행에서 사용자의 신분을 확인한다.

3. 은행에서 사용자가 금고를 열어 볼 수 있는 사람인지 판단

4. 적절한 권리나 권한이 있는 경우 금고를 열어준다.

 

1은 인증(Authentication)에 해당하는 작업으로 '증명'하는 것

3은 사용자를 '인가'하는 허가 과정

 

 

스프링 시큐리티에서 Filter는 서블릿이나 JSP에서 사용하는 필터와 같은 개념입니다.

스프링 시큐리티에서는 스프링 빈과 연동할 수 있는 구조로 설계되어 있습니다.

일반적인 필터는 스프링의 빈을 사용할 수 없기 때문에 별도의 클래스를 상속받는 형태가 많습니다.

내부에서 여러 개의 필터가 Filter Chain이라는 구조로 Request를 처리하게 됩니다.

 

필터의 핵심적인 동작은 AuthenticationManager를 통해서 인증이라는 타입의 객체로 작업하게 됩니다.

매니저가 갖고 있는 인증 처리 메서드는 파라미터도 Authentication 타입응로 받고 리턴 타입도 Authentication입니다.

 

 

실제 동작에서 전달되는 파라미터는 UsernamePasswordAuthenticationToken과 같이 토큰이라는 이름으로 전달됩니다.

스프링 시큐리티 필터의 주요 역할이 인증관련된 정보를 토큰이라는 객체로 만들어서 전달한다는 의미입니다.

 

AuthenticationProvider로 전달되는 토큰을 처리할 수 있는 존재인지 확인하고 authenticate()를 수행합니다. 

Provider는 내부적으로 UsesrDetailsService를 이용합니다.

UserDetailsService는 실제로 인증을 위한 데이터를 가져오는 역할을 합니다. JPA로 Repository를 제작했다면 UserDetailsService를 활용해서 사용자 인증 정보를 처리합니다.