SEB_BE 61일차 - Spring Security 기본1

subimm_·2022년 11월 19일
0

코드스테이츠

목록 보기
61/83

💡 오늘의 학습목표

  • Spring Security
  • Spring Security의 기본 구조
  • Spring Security의 웹 요청 처리 흐름

📔 Spring Security

  • 커피 주문 애플리케이션의 현재 문제
    • 로그인 기능 (인증,Authentication) 없음
    • API에 대한 권한 부여(인가,Authoriation) 기능 없음
    • 웹 보안 취약점에 대한 대비가 안되어있음.
  • Spring MVC 기반 애플리케이션의 인증과 인가 기능을 지원하는 보안 프레임 워크 (표준)

📖 Spring Security로 할 수 있는 보안 강화 기능

  • 다양한 유형 (폼 로그인 인증, 토큰 기반 인증, OAuth 2기반 인증)의 사용자 인증 기능 적용

  • 애플리케이션 사용자의 역할(Role)에 따른 권한 레벨 적용

  • 애플리케이션에서 제공하는 리소스에 대한 접근 제어

  • 민감한 정보에 대한 데이터 암호화

  • SSL 적용

  • 일반적으로 알려진 웹 보안 공격 차단

📖 Spring Security에서 사용하는 용어

  • Principal(주체)
    • 애플리케이션에서 작업을 수행할 수 있는 사용자, 디바이스 또는 시스템 등이 될 수 있고, 일반적으로 인증 프로세스가 성공적으로 수행된 사용자의 계정 정보를 의미
  • Authentication(인증)
    • 애플리케이션을 사용하는 사용자가 본인이 맞다는 증명 절차 의미
    • 정상적으로 수행하기 위해서는 사용자를 식별하기 위한 정보 필요 Credential (신원 증명 정보)
    • 신분증 같은 것 = Credential
    • 로그인을 위해 입력하는 패스워드 역시 로그인 아이디를 증명하기 위한 Credential
  • Authorization(인가 또는 권한 부여)
    • 인증이 정상적으로 수행된 사용자에게 하나 이상의 권한(authority)을 부여하여 특정 애플리케이션의 특정 리소스에 접근할 수 있게 허가하는 과정
    • 반드시 인증 과정 이후 수행되며, 권한은 일반적으로 역할(Role)형태로 부여됨.
  • Access Control(접근 제어)
    • 사용자가 애플리케이션의 리소스에 접근하는 행위를 제어하는 것을 의미

📔 Hello, Spring Security로 알아보는 Spring Security의 기본 구조

  • 샘플 애플리케이션에서는 SSR 방식 이용
    • 세션 기반의 폼 로그인 방식을 적용하여 학습에 적합하기 때문
  • 애플리케이션 실행 -> 회원가입 화면
  • HTML form 태그를 이용해서 회원 가입 폼을 구성하며, 폼에서 입력한 정보는 MemberController의 registerMember() 핸들러 메서드를 통해 데이터베이스에 저장됨.
    • MemberController 클래스는 JSON 응답 데이터를 클라이언트 쪽에 response body로 전송하는 것이 아니라 HTML을 렌더링해서 클라이언트 쪽에 통째로 내려주는 SSR방식의 코드로 작성됨

  • 로그인 화면
  • 로그인 화면도 HTML form 태그로 구성, Spring Security에서도 이런 방식을 폼 로그인 인증 이라고 부른다.

  • 전체 주문 목록 화면 (관리자만)
  • Spring Security 적용시, 관리자만 접근 가능한 페이지로 설정

  • 마이페이지 화면 (로그인한 사용자만)
  • Spring Security 적용시 일반 사용자만 접근 가능한 페이지
  • 샘플 애플리케이션은 SSR방식 애플리케이션으로 클라리언트에게 전송하는 HTML 코드까지 포함.
    이런 HTML뷰를 구성하기 위해 타임리프 라는 템플릿 엔진 사용

📖 Hello Spring Security 샘플 애플리케이션에 Spring Security 적용

의존 라이브러리 추가 (build.gradle)

  • 애플리케이션 실행 -> localhost:8080 접속
    • Spring Security의 자동 구성을 통해 내부적으로 제공해주는 디폴트 로그인 페이지

Spring Security에서 제공해주는 디폴트 로그인 정보

  • Username: user 입력
  • Password : 애플리케이션 실행시 출력되는 로그에서 확인
  • 문제점
    • 애플리케이션을 매번 실행시마다 패스워드가 바뀜, 회원 각자 로그인 불가, 직접 작성해 둔 로그인 페이지 사용 불가
      -> Spring Security의 Configuration을 통해 인증 방식 설정

📙 Spring Security Configuration 적용

1. Spring Security Configuration의 기본 구조

  • @Configuration 애너테이션 추가

2. InMemory User로 인증하기 ( 테스트 환경 또는 데모 환경에서 사용 )

  • Spring Security의 기본 설정 사용할 경우에 사용자의 계정 정보를 메모리 상에 지정하여 사용자 계정 정보가 바뀔일이 없다.
  • (1) UserDetails 인터페이스는 인증된 사용자의 핵심 정보 포함, UserDetails 구현체인 (2)의 User 클래스를 이용해서 사용자의 인증 정보를 생성함.
    • withDefaultPasswordEncoder() 는 디폴트 패스워드 인코더를 이용해 사용자 패스워드를 암호화한다. (1-3)의 password() 메서드의 "1111"을 암호화 해 준다.
    • username() 메서드는 사용자의 username 설정 (사람이름x, 고유한 사용자를 식별하는 아이디)
    • password() 메서드는 사용자의 password를 설정, withDefaultPasswordEncoder() 로 인해 암호화 됨.
    • roles() 메서드는 사용자의 Role, 역할을 지정하는 메서드
      일반사용자/관리자 별도 접속 기능.
  • 사용자의 핵심 정보를 포함한 UserDetails를 관리하는 UserDetailsManager 인터페이스 제공
    메모리 상에서 UserDetails 를 관리하므로 InMemoryUserDetailsManager 구현체 사용
    • (2)와 같이 new InMemoryUserDetailsManager(userDetails) 통해 객체를 Bean으로 등록하면 Spring에서는 해당 빈이 가지고 있는 사용자의 인증정보가 클라이언트의 요청으로 넘어올 경우 정상적인 인증 프로세스를 수행
  • 실무에서는 사용자 계정 정보가 데이터베이스에 저장
  • Deprecated 상태인 withDefaultPasswordEncoder()
    해당 API가 향후 버전에서는 더이상 사용되지 않고 제거될 수 있다.
    하지만 현재 메서드는 향후 버전 제거를 의미하기 보다는 Production 환경에서 인증을 위한 사용자 정보를 고정해서 사용하지 말라는 경고의 의미 (테스트 환경에서만 사용)

3. HTTP 보안 구성 기본

  • (1) HttpSecurity를 파라미터로 가지고 SecurityFilterChain 을 리턴하는 형태의 메서드 정의하면 HTTP 보안 설정 구성 가능
    • HttpSecurity는 HTTP 요청에 대한 보안 설정을 구성하기 위한 핵심 클래스.
      (SecurityFilterChain을 Bean으로 등록해서 HTTP 보안 설정 구성 방식 권장)

4. 커스텀 로그인 페이지 지정하기

  • 만들어 두었던 로그인 페이지 사용하도록 설정 추가
  • (1) CSRF 공격에 대한 설정 비활성화
    • 기본적으로 설정해주지 않으면 csrf() 공격 방지위해 클라이언트로부터 CSRF 토큰 수신 후, 검증하나 로컬환경에서 진행하므로 설정이 필요하지 않아 disable() 해줌.
  • (2) formLogin() 으로 기본적인 인증 방법을 폼 로그인 방식으로 지정
  • (3) loginPage()를 통해 우리가 템플릿 프로젝트에서 미리 만들어 둔 커스텀 로그인 페이지 사용
    • 파라미터인 "/auths/login-form" 은 AuthController의 loginForm() 핸들러 메서드에 요청을 전송하는 요청 URL
  • (4) loginProcessingUrl() 메서드를 통해 로그인 인증 요청을 수행할 요청 URL 지정
    • 파라미터인 "/process_login"은 만들어 둔 login.html에서 form 태그의 action 속성에 지정한 URL과 동일하다.
  • 템플릿 프로젝트의 login.html 코드
    • <form action="**/process_login**" method="post"> 같이 URL 지정되어있음.
    • 로그인 버튼을 클릭하면 form 태그의 action 속성에 지정된 /process_login URL로 사용자 인증을 위한 이메일주소와 패스워드를 전송
    • 요청 전송 시 해당 요청은 Spring Security에서 내부적으로 인증 프로세스 진행
  • 현재 상태에서는 login.html 커스텀 로그인 페이지를 통해 Spring Security가 로그인 인증처리를 하기 위한 요청 URL을 지정하는 것
  • (5) failureUrl(/"auths/login-form?error") 메서드를 통해 인증에 실패할 경우 어떤 화면으로 리다이렉트 할 것인지 지정.
    로그인 화면을 표시하고 실패 메세지 표시 ( 파라미터로 커스텀 로그인 페이지의 URL 지정 )
  • ${param.error} 는 Spring Security Configuration에서 failureUrl("/auths/login-form?error")?error 부분에 해당하는 쿼리 파라미터
  • (6) and() 메서드로 Spring Security 보안 설정을 메서드 체인 형태로 구성 가능
  • (7), (8), (9)로 클라이언트의 요청에 대해서 접근 권한 확인, 허용 여부 결정
    • (7) authorizeHttpRequests() 메서드로 클라 요청 시 접근 권한 확인하겠다고 정의
    • (8), (9) anyRequest().permitAll() 메서드로 클라이언트의 모든 요청에 대해 접근 허용

5. request URI에 접근 권한 부여

  • 사용자에게 부여된 Role을 이용하여 애플리케이션의 request URI에 접근 권한 부여하기
  • 사용자의 Role 별로 request URI에 접근 권한이 부여되도록 수정
  • (1) exceptionHandling().accessDeniedPage("/auths/access-denied") 로 권한이 없는 사용자가 특정 request URI에 접근할 경우 발생하는 403에러를 처리하기 위한 페이지 설정
  • authorizeHttpRequests() (2)처럼 람다 표현식으로 접근 권한 부여 가능
    • antMatchers() ant라는 빌드 툴에서 사용되는 Path Pattern을 이용해서 매치되는 URL을 표현
    • (2-1) 은 ADMIN Role 을 부여받은 사용자만 /orders로 시작하는 모든 URL에 접근 가능
    • (2-2) USER Role을 부여받은 사용자만 /members/my-page URL에 접근 가능
    • 앞에서 지정한 URL외 나머지 모든 URL은 Role에 상관 없이 접근 가능
      • antMatchers() 순서 주의
        더 구체적인 URL 경로부터 접근 권한을 부여한 다음 덜 구체적인 경로에 부여해야함

6. 관리자 권한을 가진 사용자 정보 추가

  • (1) ADMIN Role 부여한 관리자 유저 추가

7. 로그인 한 사용자 아이디 표시 및 사용자 로그아웃

  • 타임리프 기반의 HTML 템플릿에서사용자의 인증 정보나 권한 정보를 이용하여 어떤 로직을 처리하기 위해서 sec 태그를 사용하기 위한 XML 네임스페이스 지정
  • (2) 태그 내부에서 지정해주면 현재 페이지에 접근한 사용자가 인증에 성공한 사용자인지 체크
    값이 true 이면 태그 하위에 포함된 컨텐츠 화면에 표시
  • 마이페이지의 경우 ADMIN Role 에게는 필요 없는 기능이므로 (3)으로 지정해서 USER에게만 표시
  • (2) 에서 값이 true면 로그인한 사용자라는 의미로 로그인 메뉴 대신 (4)와 같이 로그아웃 메뉴 표시 ( /logout URL은 cofiguration 클래스의 설정 값과 같아야함 )
  • (5) 로그인 사용자의 username 표시
  • (6) 로그인한 사용자가 아니라면 (로그인) 버튼 표시
    • sec 태그 사용 하려면 의존 라이브러리 추가
    dependencies {
    ...
    implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5'
    }

로그아웃 기능 설정

  • (1)과 같이 logout() 메서드 먼저 호출 (로그아웃 설정을 위한 LogoutConfigurer 리턴)
  • (2) 로그아웃 수행 위한 request URL 지정
  • 로그아웃 수행 후 리다이렉트 할 URL 지정 (메인 화면)

📔 Spring Seurity의 기본 구조(2) - 데이터 베이스 연동

📖 메모리에 등록하는 InMemory User

✔ 회원 가입 폼을 통한 InMemory User
1. PasswordEncoder Bean 등록
2. MemberService Bean 등록을 위한 JavaConfiguration 구성
3. InMemoryMemberService 클래스 구현


1. PasswordEncoder Bean 등록

  • Spring Security에서 제공하는 패스워드 암호화 기능을 제공하는 컴포넌트
    회원 가입 폼에서 전달 받은 패스워드는 InMemory User로 등록되기 전 암호화 되어야함.
    • Spring Security에서 지원하는 PasswordEncoder의 디폴트 암호화 알고리즘은 bcrypt

  • (1) SecurityConfiguration 클래스에서 PasswordEncoder를 Bean으로 등록
  • (1-1) 을 통해 DelegatingPasswordEncoder 를 먼저 생성, 실질적으로 PasswordEncoder 구현 객체를 생성해 준다.

    userDetailsService() 메서드에서 미리 생성하는 InMemoryUser의 패스워드는 내부적으로 디폴트 PasswordEncoder를 통해 암호화 된다.

2. MemberService Bean 등록을 위한 JavaConfiguration 구성

  • 학습 목적으로 MemberService 인터페이스로 구현한다.
  • InMemory User 등록을 위한 InMemoryMemberService 클래스
  • MemberServic인터페이스의 구현 클래스 생성

✔ 데이터베이스에 User 등록을 위한 DBMemberService 클래스

✔ JavaConfiguration 구성

  • (1) MemberService 인터페이스의 구현체인 InMemoryMemberService 클래스의 Bean 객체 생성
    데이터베이스 연동 없이 메모리에 Spring Security의 User를 등록해야 하므로 UserDetailsManager 객체가 필요하다.
    또, User 등록 시, 패스워드 암호화 후에 등록해야하므로 PasswordEncoder 객체가 필요하다.
    이 두 객체를 InMemoryMemberService 객체 생성 시, DI 해준다.
    3. InMemoryMemberService 구현
  • @Service 애너테이션을 사용하지 않고 JavaConfiguration을 이용해 Bean으로 등록하고 있다.
  • (2) 에서는 UserDetailsManagerPasswordEncoder를 DI 받는다.
    • UserDetailsManager는 Spring Security의 User를 관리하는 관리자 역할을 한다.
      SecurityConfiguration에서 Bean으로 등록한 UserDetailsManager는 InMemoryUserDetailsManager 이므로 여기서 DI 받은 UserDetailsManager 인터페이스의 하위 타입은 InMemoryUserDetailsManager 이다.
  • Spring Security에서 User를 등록하기 위해서는 User의 권한(Authorty)를 지정해 주어야 한다. (3)의 createAuthorities를 이용해 User의 권한 목록을 List<GrantedAuthority>로 생성한다.
    • Member 클래스에 MemberRole 이라는 enum이 정의되어 있고 타입이 정의되어 있다.
      ⭐ Spring Security에서는 SimpleGrantedAuthority를 사용해 Role 베이스 형태의 권한을 지정할 때 Role_+권한명 형태로 지정해주어야 한다.
      • (3-1) 스트림을 이용해 생성자 파라미터로 해당 User의 Role을 전달하면서SimpleGrantedAuthority 객체를 생성한 후, List<SimpleGrantedAuthority> 형태로 리턴해 준다.
  • (4) PasswordEncoder를 이용해 등록할 User의 패스워드를 암호화 한다.
    • 암호화 하지 않으면 java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null” 에러
  • (5) Spring Security User로 등록하기 위해 UserDetails 를 생성
  • (6) UserDetailsManager의 createUser() 메서드를 이용해서 User 등록
  • 회원 가입 후 로그인 가능

profile
코린이의 공부 일지

0개의 댓글