Home Spring Security 요약 (~ing)
Post
Cancel

Spring Security 요약 (~ing)

이 게시물은 백기선 - Spring Security 요약임
모든 코드는 OsoriAndOmori/playground-spring 에 올려둠.
멋대로 만든 프로젝트 구조 이기 떄문에, 강좌 내용은 따라가나 구조는 절대 따라가지 않음..

1. 스프링 시큐리티 연동

  • gradle dependency 추가
1
    implementation 'org.springframework.boot:spring-boot-starter-security'
  • 추가를 하게 되면 기본적으로 모든페이지는 인증(Authentication) 을 하게됨.
  • 로그인 페이지도 기본적으로 제공이 됨.
  • 스프링 구동시 로컬 환경에서 쓸 수 있는 기본 비밀번호가 주어짐. 아이디는 user
1
2
3
2022-07-26 14:33:05.315  WARN 14922 --- [           main] .s.s.UserDetailsServiceAutoConfiguration :
Using generated security password: f93ee0c0-f58b-4f39-ab94-7805c203d2d5
This generated password is for development use only. Your security configuration must be updated before running your application in production.
  • 해결해야할 숙제
    • 인증없이 접근 가능한 URL을 설정하고 싶다.
    • 이 애플리케이션을 사용할 수 있는 유저 계정이 그럼 하나 뿐인가?
    • 비밀번호가 로그에 남는다고?

2. 인증없이 접근 가능한 URL 설정

  • SecurityFilterChain Bean 등록하면 끝임.
  • chaning 형태로 and() 활용하여 예쁘게 쓸 수도 있고 그냥 끊어서 해도 상관없음.
  • 아래 예제는 /, /info 는 모두에게 접근 허용하고, /admin 의 경우에는 ADMIN role 을 가지고 있는 자만이 접근 가능함.
1
2
3
4
5
6
7
8
9
10
11
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .mvcMatchers("/", "/info").permitAll()
                .mvcMatchers("/admin").hasRole("ADMIN")
                .anyRequest().permitAll();
        http.formLogin(); //폼로그인
        http.httpBasic(); //http 기본 로그인

        return http.build();
    }

3. jpa & database 연동

  • jpa 쓰고 싶으니깐 jpa dependency 추가 하고 테이블이랑, repository 하나 만들어줌
1
  implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public interface AccountRepository extends JpaRepository<Account, Integer> {
    Account findByUsername(String username);
}

@Entity
@Data
public class Account {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Integer id;
  @Column(unique = true)
  private String username;
  private String password;
  private String role;

  //spring security 가 원하는 기본적인 비밀번호 포맷 {알고리즘}
  public void encodePassword() {
    setPassword("{noop}" + getPassword());
  }
}
  • db 연동시 핵심은 UserDetailsService 를 구현한 Bean 이 있어야함. 등록만 하면 바로 적용됨.
  • 여기까지 새로운 문제
    • {noop} 을 없앨 수는 없을까?
    • 테스트는 매번 화면키고 해야 하는건가?

4. Password Encoder 적용

  • spring 5 이전엔 따로 PasswordEncoder 없이, 그냥 문자 그대로 저장했었음. (아님 사용자가 직접 해시 알고리즘 써서 비번 바꾸거나겠지?)
  • 왜 맨 앞에{noop}포맷이 생겼을까라고 한다면, 4.x 대 까진 NoOpPasswordEncoder 가 기본이었는데 버전을 올리면 Bcrypt 로 변경됨
    • 그러다보니 버전업을하면 인증이 전부 꺠지게됨… 그래서 앞에 prefix 를 통해, 여지를 주기위해 포맷을 저렇게 잡았음.
  • 아래 bean 을 추가해주고 최초 유저 집어넣을 떄 비번 encoding 한번 해주자.
  • 그러면 기본 bcrypt 로 셋팅 되어서 비밀번호가 저장됨. 원하면 포맷을 {MD5}도 변경할 수 있음.
  • 로그인시 PasswordEncoder bean 이용해서 인증 실시함.
    1
    2
    3
    4
    5
    6
    7
    8
    
      @Bean
      public PasswordEncoder passwordEncoder() {
          return PasswordEncoderFactories.createDelegatingPasswordEncoder();
      }
    
      public void encodePassword(PasswordEncoder passwordEncoder) {
          this.password = passwordEncoder.encode(this.password);
      }
    

    image

  • 여기까지 새로운 문제
    • 테스트는 매번 화면키고 해야 하는건가?

5. Spring security test

  • 화면 키고 테스트하기 매우 귀찮음.
  • @WithMockUser(username = "admin", roles = "ADMIN") 같은걸 사용해서 유저 권한 체크 가능함
1
2
3
4
5
6
7
8
9
10
11
    @Test
    @Transactional
    void login() throws Exception {
        String username = "sky-test2";
        String password = "sky-test2";

        Account user = createUser(username, password);

        mockMvc.perform(formLogin().user(user.getUsername()).password(password))
                .andExpect(authenticated());
    }

6. Spring Security Architecture

1. SecurityContextHolder 와 Authentication

  • SecurityContextHolder
    • ThreadLocal 에서 SecurityContext 제공함.
    • ThreadLocal 은 한 쓰레드 내에서 공유하는 저장소라고 일단 생각 (메서드 파라미터로 안넘겨도 가져올 수 있는 데이터)
      1
      
      SecurityContext.getContext().getAuthentication() //하면 해당 요청의 인증정보 꺼낼 수 있음.
      
  • Authentication 의 실제 구현체 UsernamePasswordAuthenticationToken 같은 클래스로 구현되어있고 폼로그인시 요걸 사용함.
  • AuthenticationManager
    • SecurityContextHolder 가 Authentication 을 들고 있는거고 얘는 실제 인증을 담당하는 매니져임
    • 내부에 authenticate 메서드 하나만 들고 있음.
    • 실제 구현체는 ProviderManager 를 사용함. debuger 를 여기다 찍고 한번 보셈.
This post is licensed under CC BY 4.0 by the author.

Spring batch Mysql + JdbcCursorReader 사용시 확인할 점

정해진 미래