카테고리 없음

부트캠프95일차 (springSecurity)

동곤일상 2025. 6. 30. 16:31
반응형

 

 

 

 


1) springSecurity 정의

1) 정의

  • 웹 애플리케이션의 보안을 담당하는 프레임워크
  • 애플리케이션에서 인증(Authentication)과 권한(Authorization)을 처리하는 기능 제공
  • 이를 통해 로그인, 접근 제어, 보안 정책 쉽게 구현 가능

2) 인증과 권한

(1) 인증(Authentication)

  • 사용자의 신원을 확인하는 과정
  • 일반적으로 로그인이 이에 해당함

(2) 권한(Authorization)

  • 사용자가 특정 리소스에 접근할 수 있는 권한이 있는지 확인
  • 예: 일반 사용자는 관리자 페이지에 접근할 수 없음

 

작업

일단 pom.xml의 DB관련설정은 주석처리해보자


커스텀로그인

  • Spring Security의 환경설정 코드를 구성할때 주로 사용
  • 람다식이 아닌 코드를 찾는다면 적용이 불가능할 가능성 높음
  • authorizeHttpRequests 메소드에 전달되는 객체를 requests라고 이름 지어

 

적용

 

2) 프로젝트생성 및 security적용

 

스프링부트로만들고 maven기반의 프로젝트로만들어주자

해당 의존성추가하기

 

applcation.properties

spring.application.name=springSecurity2
server.port=8080

spring.datasource.driver-class-name=org.mariadb.jdbc.Driver
spring.datasource.url=jdbc:mariadb://localhost:3306/gdjdb
spring.datasource.username=gduser
spring.datasource.password=1234

spring.jpa.hibernate.ddl-auto=update

#entity명이 낙타표기법이라면 _ 로 구분해저장
#spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.CamelCaseToUnderscoresNamingStrategy

#entity명 평문으로 저장
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl

 

 

controller/HomeController

package springSecurity2.controller;


import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

@Controller("/")
public class HomeController {

    @GetMapping
    public String root(Model model) {
        model.addAttribute("msg","홈으로이동합니다");
        return"home";
    }

    @GetMapping("home")
    public String home(Model model) {
        model.addAttribute("msg","home");
        return "home";
    }

    @GetMapping("my")
    public String my(Model model) {
        model.addAttribute("msg","my");
        return "home";
    }

    @GetMapping("admin")
    public String admin(Model model) {
        model.addAttribute("msg","admin");
        return "home";
    }

    @GetMapping("login")
    public String login(Model model) {
        return "login";
    }
}

각각 다른url요청을 받지만 반환값은 같음

 


resourse/ templates/ home 은 그냥 msg만 띄워주는용도로 만들어놨으므로 생략

 


config/SecurityConfig

@Configuration
@EnableWebSecurity //Spring Security를 활성화
public class SecurityConfig {
    @Bean
    public HttpSessionEventPublisher httpSessionEventPublisher() {
        return new HttpSessionEventPublisher();
    }

    /*
    HttpSecurity : spring Security 보안설정 담당객체 (HTTP요청시 인증,권한을 정의가능)
    authorizeHttpRequests : 요청 URL에 따라 권한설정
    requestMatchers : 요청url
    permitAll() : 모두허용
    anyRequest() : 그 외의 모든요청
    authenticated : 인증받아야함
     */
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests((auth)->auth
                .requestMatchers("/","/home").permitAll() //home은 누구나 접근가능하다
                .anyRequest().authenticated());
        return http.build();
    }
}

요약 :  /g혹은 /home 으로 요청된 URL은 누구나 접근이 가능하다

        다른 요청 URL은 인증이 필요하다

 

/ or /home으로 접근시

 

/my or /admin  or /xx 접근시


 

3) 커스텀로그인 , 로그아웃

 

config/SecurityConfig의SecurityFilterChain메서드의 일부

package springSecurity2.config;

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.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.session.HttpSessionEventPublisher;


@Configuration
@EnableWebSecurity //Spring Security를 활성화
public class SecurityConfig {
    @Bean
    public HttpSessionEventPublisher httpSessionEventPublisher() {
        return new HttpSessionEventPublisher();
    }

    /*
    HttpSecurity : spring Security 보안설정 담당객체 (HTTP요청시 인증,권한을 정의가능)
    authorizeHttpRequests : 요청 URL에 따라 권한설정
    requestMatchers : 요청url
    permitAll() : 모두허용
    anyRequest() : 그 외의 모든요청
    authenticated : 인증받아야함
     */
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
...............

        //커스텀로그인
        //loginPage("/login")로 인해 인증되지 않은 사용자가 보호된 URL에 접근하면 /login으로 리다이렉트됩니다.
        http.formLogin((a)->a.loginPage("/login") //로그인요청
        .loginProcessingUrl("/loginProc").permitAll()); //로그인 form의 action값

        http.logout((a)->a.logoutUrl("/logout")
                .logoutSuccessUrl("/login") //성공시 login 페이지로
                .invalidateHttpSession(true)//세션초기화
                .deleteCookies("JSESSIONID")//JSESSIONID(session)삭제
                .permitAll());//누구나 접근가능
        return http.build();
    }

    @Bean
    public BCryptPasswordEncoder bcryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

알아야할것!

 

페이지에 session이 등록됐다면 cookie의 JSESSIONID가 활성화

 

 

http.formLogin((a)->a.loginPage("/login").....)으로 인해  

인증되지않은 사용자가 보호된 URL로접근하면 login페이지로 강제 리다이렉트 되게 됨

 

 

 


4) BCrypt(security에서 제공)

 

 

테스트코드를 이용해 BCrypt가 무엇인지 설명하겠음

일단 Bcrypt는 단방향 암호화키라고 보면 됨

(평문으로 복호화가 불가능 하며 matches를 통해 비교만할수있다)

package springSecurity2;

import org.junit.jupiter.api.Test;
import org.springframework.security.crypto.bcrypt.BCrypt;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;


public class TestBcrypt {
    public static void main(String[] args) {
        System.out.println("new BCryptPasswordEncoder().encode('123');");
        String encode = new BCryptPasswordEncoder().encode("123");
          String encode2= new BCryptPasswordEncoder().encode("123");
        System.out.println("123 -> : "+encode);
        System.out.println("123 -> : "+encode2);

        System.out.println("\n검증은 BCryptPasswordEncoder().matches(암호화x,암호화O)");
        boolean matches1 = new BCryptPasswordEncoder().matches("123", encode);
        boolean matches2 = new BCryptPasswordEncoder().matches("15523", encode);
        System.out.println("123? : "+matches1);
        System.out.println("15523? : "+matches2);


    }

}

 

다음과같은 출력이 나오게 됨 

new BCryptPasswordEncoder().encode('123');
123 -> : $2a$10$OvaTYKPHADa8DzH0zdkLBufKpHvK1dyJI7lYTZZ66eJjbknlkJZvq
123 -> : $2a$10$hnVENFmS.uWV8IPc/IX8E.H0mGR9mo258sfMR7cHbKq1tntupWZ0e

검증은 BCryptPasswordEncoder().matches(암호화x,암호화O)
123? : true
15523? : false

 

 

여기서 주목해봐야할 점이 하나 있음

똑같은 123을 똑같은 방법(Bcrypt)를 이용해 암호화를 진행했는데
암호화된 키의 값이 다르다???

즉 복호화를 절대로 할 수 없다고 생각하면 된다