728x90

Spring Security 예제

우선 코드는 깃허브에 있다.

일단 문서로 정리한 것을 토대로 로그인과 회원가입 어떤 순서로 동작하는지 알아보려고 했다.

로그인

일단 시큐리티에 대한 설정은 SecurityConfig 라는 클래스 설정파일을 만들어서 진행했다.

WebSecurityConfigurerAdapter

WebSecurityConfigurerAdapterWebSecurityConfigurer 라는 인터페이스를

조금 더 쉽게 생성하기 위해 존재하는 클래스이다. 이 클래스의 구현을

그러니까 기본으로 적용되어 있는것 외에 재정의 하여 사용할 수 있다.

아래는 해당 추상클래스에 대한 설명을 가져와봤다.

스크린샷 2021-12-05 오후 8 51 54

우리는 이 추상 클래스에서 구현되어있는 configure(HttpSecurity http) 메소드를 재정의 하여 설정을 진행한다.

스크린샷 2021-12-05 오후 8 55 19

SecurityConfig

package io.github.lsj8367.security.configuration;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/", "/h2-console/**"); // "/" 와 "/h2-console"은 접근 가능
        //여기서 무시하는 과정이 아래의 configure()보다 우선순위가 높다.
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
            .anyRequest().authenticated() //모든 요청은 인증이 필요함 위의 ignoring()에 포함된 애들은 제외시킨다. 추가적으로 permitAll()로 해제해준 url은 접근 가능
            .and()
            .formLogin() //formLogin 설정 default /login
            .and()
            .logout().permitAll(); //logout에 대한 모든권한 적용 default /logout
    }

}

여기 설정에서 formLogin()은 uri를 잡아주지 않았기에 기본값인 /login으로 로그인을 처리한다.

UsernamePasswordAuthenticationFilter

이때 동작하는 필터가 UsernamePasswordAuthenticationFilter인데 이 클래스는

AbstractAuthenticationProcessingFilter를 상속받아 처리해준다.

UsernamePasswordAuthenticationFilter 클래스는 기본값인 /login에 대해 응답한다고

설명에 명시되어 있다. 여기서 사용되는 username, passwordconfigure()에서

usernameParameter()passwordParameter()로 변경해서 매칭해줄 수 있다.

인증에 대한 검증을 수행하게 되는데

스크린샷 2021-12-05 오후 9 07 52

HTTP 메소드가 POST인지를 먼저 판단한다.

그 후에 obtainUsername, obtainPassword로 파라미터 설정한것을 가져온다.

나는 기본값으로 두었기에 form안에 input id가 username, password 이다.

그다음에 null인지, 빈문자열인지 검증을 한 뒤에

UsernamePasswordAuthenticationToken을 발급해준다.

이렇게 로그인 인증이 일단락 되었다.

728x90

'Spring > Security' 카테고리의 다른 글

Authentication 인증  (0) 2022.08.09
개요  (0) 2022.08.09
728x90

스프링 시큐리티 사용자 인증

스프링 시큐리티는 인증에 대한 정보들을 제공한다.

Servlet Authentication Architecture

인증에 대한 아키텍처는 아래와 같다.

  • SpringSecurityContextHolder
    • 인증된 사용자의 세부 정보를 저장하는 곳
  • SecurityContext
    • SpringSecurityContextHolder에서 가져온 현재 인증된 사용자 인증을 가지고 있다.
  • Authentication
    • 사용자가 인증을 위해 제공한 자격증명이나 현재 사용자를 제공하기 위한 AuthenticationManager의 입력이 될 수 있음
  • GrantedAuthority
    • 인증에 대한 권한 정보
  • AuthenticationManager
    • 스프링 시큐리티 필터가 인증을 수행하는 방법을 정의
  • ProviderManager
    • AuthenticationManager의 기본 구현체
  • AuthenticationProvider
    • ProviderManager에서 특정 유형의 인증을 진행하는 Provider
  • Request Credentials with AuthenticationEntryPoint
  • AbstractAuthenticationProcessingFilter
    • 인증에 사용되는 기본 필터

SecurityContextHolder

구조

일반적인 구조는 위와같이 생겼다.

설명

스프링 시큐리티가 인증된 사용자의 정보를 저장하는 곳이다.

값이 포함되어 있으면 현재 인증된 사용자로 사용된다.

Authentication

사용자가 인증을 위해 제공한 자격 증명 AuthenticationManager 입력값.

이 상태에서 isAuthenticated()false를 반환

현재 인증된 사용자를 반환 현재 인증은 SecurityContext에서 얻을 수 있다.

Authentication이 포함하고 있는 값들

  • principal
    • 사용자를 식별한다.
    • username, password로 인증할 때 UserDetails가 값들을 포함한다.
  • credentials
    • 비밀번호
    • 이 비밀번호는 유출되지 않게 사용자를 인증 후 지워진다.
  • authorities
    • GrantAuthority 권한을 포함한다.

GrantAuthority

사용자에게 부여된 상위 수준의 권한

이 객체는 Authentication.getAuthorities() 에서 얻을 수 있다.

이 권한은 인증받으려는 주체에게 부여된 권한이다.

이 권한은 흔히 말하는 사용자, 관리자 등등 해당 권한을 나타낸다.

이 역할로 특정 URI에 대한 권한이나 접근 권한을 제어할 수 있게 된다.

username, password 기반 인증을 사용할 시에 권한은 UserDetailService가 가지고 있다.

UserDetailService

이 클래스는 AuthenticationProvider에서 username, password로 인증하기 위해

해당 사용자 이름, 비밀번호, 기타 속성들을 검색하는데에 사용된다.

UserDetailService를 커스텀 Bean으로 정의할 수 있다.

AuthenticationManager

이 클래스는 스프링 시큐리티 필터가 인증을 수행하는 방법을 명시한 API이다.

반환되는 인증은 AuthenticationManager를 호출한 컨트롤러에 의해

SpringSecurityHolder에 설정된다.

스프링 시큐리티의 필터와 통합하지 않는 경우에는 SecurityContextHolder를 직접

설정 할 수 있고, AuthenticationManager를 사용할 필요가 없어진다.

AuthenticationManager의 구현은 어떤것이든 가능하지만, 기본 구현은 ProviderManager

ProviderManager

위에서 말했듯, 이 클래스는 AuthenticationManager의 구현체이다.

ProviderManagerAuthenticationProviders의 리스트에 위임한다.

AuthenticationProvider는 성공, 실패를 나타내거라 결정할 수 없고

다운스트림 AuthenticationProvider가 결정하도록 허용할 수 없다.

AuthenticationProvider중 어느 것도 인증을 할 수 없는 경우에는

인증 예외인 ProviderNotFoundException이 발생하여 인증이 실패하게 된다.

구조

설명했듯 각 provider들이 특정 유형의 인증을 수행한다.

ProviderManagerAuthenticationProvider가 인증을 수행할 수 없는 경우

상위의 AuthenticationProvider를 설정하여 구성이 가능하다.

상위 AuthenticationProviderProviderManager의 인스턴스이다.

스크린샷 2021-12-03 오후 10 44 17

AuthenticationProvider

ProviderManager에 여러 AuthenticationProvider를 주입할 수 있다.

AuthenticationProvider들은 저마다의 특정 유형 인증을 수행하게 되어있다.

예를 들어, DaoAuthenticationProvider는 이름/암호 기반의 인증을 사용하고,

JwtAuthenticationProvider는 Jwt 토큰 인증을 사용한다.

AbstractAuthenticationProcessingFilter

이 클래스는 사용자의 자격 증명을 인증하기 위한 기본 필터이다.

이 인증이 되기전에 AuthenticationEntryPoint를 사용하여 HTTP 요청을 한다.

Authentication으로 인증에 대한 정보들을 쭉 가져온다.

AuthenticationManager가 그 인증 정보들을 받아 여러 검증들을 수행한다.

성공하면 Success 기본 호출은 AuthenticationSuccessHandler, 실패하면 Failure로 가서 AuthenticationFailureHandler호출됨

728x90

'Spring > Security' 카테고리의 다른 글

로그인 동작 순서  (0) 2022.08.09
개요  (0) 2022.08.09
728x90

📌 Spring Security

Spring SecurityServlet Filters를 기반으로 동작한다.

Spring Security는 인증, 권한 부여 및 보호를 제공하는 프레임워크이다.

스크린샷 2021-12-03 오후 10 38 42

전체적인 구조는 위와 같다.

Gradle 설정

plugins {
      id 'io.spring.dependency-management' version "1.0.10.RELEASE"
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-security'
}

📌 Filter

그래서 필터의 역할을 먼저 아는것이 중요한데,

Filter 영어 단어만 봐도 뭔가를 필터로 걸러주는 느낌이 난다.

업무중에 통신 하나하나의 로그를 다 찍는 과정을 Filter를 통해서 구현했던 경험이 있다.

이 필터를 줄줄이 연결하면 FilterChain이 되는 것이다.

다음은 스프링 공식문서에서 FilterChain의 구조를 가져왔다.

구조

스크린샷 2021-12-01 오후 9 19 39

클라이언트는 서버에 요청을 보내고 컨테이너는 요청 URI를 기반으로 HttpServletRequest를 처리하는 필터와

필터체인을 생성한다. Spring MVC에서의 ServletDispatcherServlet이 된다.

Filter 인터페이스를 구현하면 doFilter(ServletRequest request, ServletResponse response, FilterChain chain)

메소드를 구현해주어야 한다.

chain.doFilter()를 호출하면 다음 필터를 차례대로 수행하는 것이다.

이렇게 필터들이 쭉 연결되어 기능을 수행한다고 생각하면 된다.

📌 DelegatingFilterProxy

구조

스크린샷 2021-12-01 오후 9 30 41

설명

SpringServlet 컨테이너의 라이프사이클과

SpringApplicationContext 사이의 연결을 허용하는

DelegatingFilterProxy라는 필터를 제공한다.

이 필터는 Servlet Filter로 애플리케이션 컨텍스트에서 요청한 것을 스프링 컨테이너에 생성된

Bean Filter를 찾고 그 필터를 호출한다.

DelegatingFilterProxy는 컨테이너가 시작되기 전에 필터를 등록해야 하기 때문에 중요하다.

📌 FilterChainProxy

Spring Security의 서블릿 지원은 FilterChainProxy에 포함되어 있다.

FilterChainProxySecurityFilterChain을 통해 여러 필터 인스턴스에 위임할 수 있도록

시큐리티에서 제공하는 특수 필터이다.

FilterChainProxyBean이라서 DelegatingFilterProxy안에 포함된다.

구조

스크린샷 2021-12-01 오후 9 45 51

이제보니 구조가 좀 잡혀가는것 같다.

클린코드와 자바의 정석을 읽었더니 시큐리티 아키텍처가 이해되는건 무엇일까.... 🤔🤔🤔

📌 SecurityFilterChain

SecurityFilterChain은 클라이언트에서 필터를 돌다가 DelegatingFilterProxy에 들어온 요청을

받아서 이 요청에 대해 처리해야 하는 Security Filter를 찾아 수행한다.

구조

스크린샷 2021-12-01 오후 9 57 39

📌 Security Filter

핵심인 시큐리티 필터이다. 이 필터는 SecurityFilterChain API를 사용해

FilterChainProxy에 삽입된다. 이 필터들은 순서가 중요하다.

필터의 순서를 알 필요는 없다.

근데 알아두면 유용하게 사용할 수는 있다.

필터에는 다음과 같은 필터들이 존재하고 위에서 아래로 순서가 매겨져 있다.

  • ChannelProcessingFilter
  • WebAsyncManagerIntegrationFilter
  • SecurityContextPersistenceFilter
  • HeaderWriterFilter
  • CorsFilter
  • CsrfFilter
  • LogoutFilter
  • OAuth2AuthorizationRequestRedirectFilter
  • Saml2WebSsoAuthenticationRequestFilter
  • X509AuthenticationFilter
  • AbstractPreAuthenticatedProcessingFilter
  • CasAuthenticationFilter
  • OAuth2LoginAuthenticationFilter
  • Saml2WebSsoAuthenticationFilter
  • UsernamePasswordAuthenticationFilter
  • OpenIDAuthenticationFilter
  • DefaultLoginPageGeneratingFilter
  • DefaultLogoutPageGeneratingFilter
  • ConcurrentSessionFilter
  • DigestAuthenticationFilter
  • BearerTokenAuthenticationFilter
  • BasicAuthenticationFilter
  • RequestCacheAwareFilter
  • SecurityContextHolderAwareRequestFilter
  • JaasApiIntegrationFilter
  • RememberMeAuthenticationFilter
  • AnonymousAuthenticationFilter
  • OAuth2AuthorizationCodeGrantFilter
  • SessionManagementFilter
  • ExceptionTranslationFilter
  • FilterSecurityInterceptor
  • SwitchUserFilter

블럭이 쳐져있는 필터들을 유의해서 더욱 살펴봐야 하겠다.

📌 Handling Security Exceptions

위에서 ExceptionTranslationFilter를 사용하면 AccessDeniedException이나,

AuthenticationException을 HTTP Response로 변환할 수 있다.

스크린샷 2021-12-01 오후 11 16 45
  1. 일단 들어온 요청에서 FilterChain.doFilter()로 나머지 애플리케이션을 호출한다.
  2. 사용자가 인증이 되지 않았거나, AuthenticationException이 발생한 경우에 인증을 진행한다.

    이 경우 사용자가 성공적으로 인증되면 RequestCache에 사용자를 저장하고 이 캐시를 사용하여 원래 요청을 쭉 진행한다.
  3. 여기서 AccessDeniedException이 발생하게 되면 액세스는 거부되고, AccessDeniedHandler는 이 예외를 처리하기 위해 호출된다.

이 설정이 AccessDeniedExceptionAuthenticationException에 대한 예외처리가 없다면

ExceptionTranslationFilter는 아무것도 수행하지 않는다.

정리

여기까지가 일단 스프링 시큐리티의 기본적인 흐름이다.

다음 포스팅에서는 인증(Authentication) 에 대해서만 쭉 다뤄보는것으로 하겠다.

어렴풋이 알고 있는 기본값들에 대해서만 사용할게 아니라 입맛에 따라 커스텀하며 필터를 작업해주는 것이

개발자의 역량이라고 생각한다. 이게 뒷받침되려면 당연히 이런 공식문서를 읽어보는게 답이다.

전체적인 아키텍처의 흐름을 알아야 잘 설계할 수 있다.

아무튼 이 아키텍처를 공부함으로써 어제의 나보다는 오늘이 더 성장했다.

업무나 프로젝트에 들어간 시큐리티에 대한 코드를 보면 지금보다 더 이해할거라고 자신한다 🔥🔥🔥🔥

728x90

'Spring > Security' 카테고리의 다른 글

로그인 동작 순서  (0) 2022.08.09
Authentication 인증  (0) 2022.08.09
728x90

필터와 인터셉터

사이드 프로젝트를 하면서, 그리고 최근 회사의 프로젝트를 진행하면서

로깅처리와 더불어 어떠한 인증에 관한 것을 처리할 때 항상 필터를 구현했다.

이 필터가 뭔가 했더니 내가 옛날에도 들었었던 지식이지만 그냥 넘어가는 경우였고,

하다못해 스프링 동작과정에 정리해도

필터와 인터셉터에 관한 내용은 빼먹고 업로드를 한 것같다.

image

스프링 mvc의 기본 흐름에 대한 조금 더 구체적인 그림을 가져왔다.

다른 플로우차트를 찾아보려고 했지만 없더라.

실행

일단 서블릿 Request요청이 오게되면 바로 Filter로 가게된다.

여기서 무조건 동작을 받아서 처리를 해주고 이 필터들이 쭉 이어진것이 바로 필터체인이다.

image

필터 내부의 설명에서 보는것과 같이 doFilter 이 메소드에서 필터링을 수행하기 때문에

필터를 하나하나 등록해주게 되면 스프링은 요청을 받을때 저 필터들을 쭉쭉 통과해 나간다.

그다음에 DispatcherServlet으로 가게 되는 것이다.

서버를 실행시키면 Servlet이 올라오는 동안 init이 실행될 것이고

그 후에 doFilter가 수행될 것이다.

필터

이 필터는 아까도 말했듯, DispatcherServlet 이전에 실행되기 때문에 뭔가를 걸러주거나, 요청내용을 변경, 그리고 말했던 로깅처리 등을 진행할 수도있다.

public interface filter {
    public default void init(FilterConfig filterConfig) throws ServletException{}// - 필터 인스턴스 초기화

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException;// - 전/후 처리

    public default void destroy() {}// - 필터 인스턴스 종료
}

이런식으로 세가지의 구성으로 되어있다.

image

doFilter에 있는 ServletRequest 객체는 매개변수 이름, 값 속성 등을

포함하는 데이터를 제공해준다.

web.xml에서 정리할 수도 있고, 나는 스프링 부트를 쓰기 때문에

javax.servlet.Filter를 구현해 주었다.

인터셉터

인터셉터는 말 그대로 가로채기이다.

필터는 스프링 외적으로 존재해서 스프링과는 상관없는 자원에 동작한다.

인터셉터는 DispatcherServlet 이 컨트롤러를 호출하기 전,후에 가로채려고 하기 때문에

스프링 컨텍스트 내부에서 Controller에 관한 요청, 응답에 대해 관여할 수 있다.

인터셉터는 여러 개를 사용할 수 있고 로그인 체크, 권한체크, 프로그램 실행시간 계산작업 로그확인 등의 처리가 가능하다.

  • preHandler()
    • 컨트롤러 메서드가 실행되기 전
  • postHanler()
    • 컨트롤러 메서드 실행직 후 view페이지 렌더링 되기 전
  • afterCompletion()
    • view페이지가 렌더링 되고 난 후

image

동작과정을 보면 이해가 될 수 있다.

지금 내 사이드 프로젝트에서 로그인 세션 null체크 기능이 잡다하게 중복이 되어있다.

도대체 학원에선 왜 이렇게 해도 뭐라안했을까 싶은 그런 로직들..

이 개념을 좀 도입해서 로깅처리와 로그인 기능을 좀 더 단순하게 구성을 해야겠다.

조바심 느끼지말고 남하고 비교하지말고 어제의 나보다만 성장해있으면 되는것 같다.

728x90

'Spring' 카테고리의 다른 글

Service Layer에 대한 생각  (0) 2022.08.10
Validaion  (0) 2022.08.09
Jasypt  (0) 2022.08.07
Spring -> Spring Boot 마이그레이션 2  (0) 2022.08.06
728x90

비교적 오랜만에 글을 업로드 하는 것 같다.

사이드 프로젝트와 여러가지 업무에 매진해서 블로그 포스팅할 새도 없이 쭉 지나갔다.

모든 코드는 깃허브에 있다.

이번 포스팅에서는 Encyption 즉, 암호화에 대해서 다뤄보겠습니다.

서론

우선 현재 저희가 쓰고있는 암호화에는 각종 Open Api 클라이언트 ID와 비밀번호에 대해 암호화를 적용하였습니다.

스크린샷 2021-09-12 오후 8 37 13

예시로 하나의 암호화된 아이디와 패스워드를 가져왔습니다.

Github 또는 그 외의 공개 장소에 프로젝트 관리를 하다보면 DB 패스워드 등 보안에 민감한 정보들이 노출되기 쉽습니다.

그렇기 때문에 이런 민감한 정보들은 암호화를 해주어야 합니다.

그냥 명시적으로 적어두게 되면 누군가가 이 아이디와 암호를 보고 같이 사용할 수 있기 때문입니다.

Jasypt 라이브러리

일단 모든 설명은 공식문서와 깃허브에서 가져왔음을 알립니다.

Encrption이라는 키워드로 검색했을 때 Jasypt 라는 라이브러리가 자주 등장했습니다.

Jasypt는 자바에서 암호화를 쉽게 할 수 있도록 도와주는 라이브러리였습니다.

나는 Spring에서 프로젝트가 실행될 때 암호화를 해제하는걸 원했는데 딱 원하던 내용을 찾을 수 있었습니다.

@Bean("jasyptStringEncryptor")
public StringEncryptor stringEncryptor() {
    PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
    SimpleStringPBEConfig config = new SimpleStringPBEConfig();
    config.setPassword("password");
    config.setAlgorithm("PBEWITHHMACSHA512ANDAES_256");
    config.setKeyObtentionIterations("1000");
    config.setPoolSize("1");
    config.setProviderName("SunJCE");
    config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");
    config.setIvGeneratorClassName("org.jasypt.iv.RandomIvGenerator");
    config.setStringOutputType("base64");
    encryptor.setConfig(config);
    return encryptor;
}

공식 문서에는 이렇게 Bean을 세팅하여 주입하는 식으로 설명이 되어있었습니다.

스크린샷 2021-09-12 오후 8 49 17

이 암호화 Configuration 설명을 보시면 키들이 properties 형식으로 작성이 되어있기에 저희 프로젝트의

yaml 형식으로 바꾸어

jasypt:
  encryptor:
    password: "비밀번호"

를 만들고 타고 들어갔을때의 내부 구현 클래스의 사진을 가져왔습니다.

스크린샷 2021-09-12 오후 8 47 51

properties의 설명은 당연히 jasypt.encryptor의 하위에 소스들을 읽어 들여서
세팅을 해주게 되어있습니다.

이미지를 부분만 캡쳐하여 가져왔기 때문에 보이지는 않지만,

조회해본 결과 password 외에는 전부 기본값이 설정이 되어 적용되어 있음을 확인하였습니다.

ENC() 문자열로 감싸준 이유는 암호화문을 ENC 괄호안으로 넣어주었을 경우

설정해준 jasypt.encryptor.password의 값을 읽은 후 복호화를 진행해줍니다.

저는 아래와 같이 테스트코드를 작성하여 암호를 설정해 암호화를 진행했습니다.

public class JasyptTest {
    @Test
    void jasyptTest() {
        StandardPBEStringEncryptor pbeEnc = new StandardPBEStringEncryptor();
        pbeEnc.setAlgorithm("PBEWithMD5AndDES");
        pbeEnc.setPassword("사용할 암호");

        String clientId = pbeEnc.encrypt("암호화 하려는 아이디");
        String password = pbeEnc.encrypt("암호화 하려는 비밀번호");

        System.out.println(clientId);
        System.out.println(password);
    }
}

고민사항

여기서 암호화를 하는 과정은 알게 되었습니다.

여기서 했던 고민은 결국 이 비밀번호도 어딘가에 저장해야 하는데

어떻게 저장해야 할까?

가 관건이었습니다.

회의를 통해 나온 결론은 모든 암호화는 지금처럼 적용하되, 해당 암호에 대한 설정은

각자의 컴퓨터의 환경변수로 잡아주자 라는 결론으로 모아졌습니다.

그래서 저희는 환경변수로 잡아주었습니다.

저는 맥의 환경이었으므로 이렇게 진행하였습니다.

cd ~
vi .profile/

# vi 에디터 사용하여 쉘 스크립트 작성으로
export JASYPT_PASSWORD="패스워드"
:wq

source ~/.profile

를 해주었습니다.

이 환경변수를 잡는 과정에서 상당히 많은 이슈가 발생했었는데요 😭

일단 저희는 깃허브 CI, CD를 사용하고 있기 때문에

push를 하게 되면 이후의 깃허브 가상 도커 컨테이너에서 빌드를 진행하여 저 부분에 대해서는 환경변수를 넣기 애매했습니다.

그리고

java build -DJASYPT_PASSWORD
java test -DJASYPT_PASSWORD

이런 명령어들 마다 계속 값 세팅이 달라졌기 때문에 하나가 성공하면 하나가 실패하는 그런 케이스가 지속이 되었습니다.

깃허브에서는 어떻게 환경변수를 넣을까 공식문서를 찾아본 결과

env:
      JASYPT_PASSWORD: ${ secrets.JASYPT_PASSWORD } # 중괄호 2개 사용해야함

CI,CD yaml파일에 다음과 같이 추가를 해주면 환경변수로 잡아줄 수가 있었습니다.

jobs:
  build:
    runs-on: ubuntu-latest
    env:
      JASYPT_PASSWORD: ${ secrets.JASYPT_PASSWORD } # 중괄호 2개 사용해야함

secrets는 깃허브 Action 설정에서 전역으로 JASYPT_PASSWORD 라는 키에 저희 암호를 넣어주고 ${} 형식으로 불러올 수가 있습니다.

이렇게 하고 명령어를 써주어 암호화를 진행할 수 있게 되었습니다.

이 부분이 깊게는 알아서 쓰는것은 아니고 단순히 암호화를 하여 소스를 가리는 목적으로만 사용해서

이정도 깊이정도만 학습해도 별 문제없이 쓸수 있을정도의 라이브러리 였기 떄문에 여기까지만

알아보도록 하겠습니다.

정리

팀 프로젝트를 협업하면서 이번 부분에서 보안에 굉장히 많은 시간을 제가 투자하고 있는것 같습니다.

처음 적용 시켜보지만 디버깅과 깊게 조사하면서 배우니까 확실히 제껄로 만들어가는 느낌이 굉장히 좋습니다.

728x90

'Spring' 카테고리의 다른 글

Validaion  (0) 2022.08.09
Filter, Interceptor 정리  (0) 2022.08.07
Spring -> Spring Boot 마이그레이션 2  (0) 2022.08.06
Spring Data JPA  (0) 2022.08.06
728x90

삽질기

모든 코드는 깃허브에 있다.

일단 저번에 마이그레이션 1탄을 했었는데 의존성이 겹쳐서 다시 리팩토링 하려고 보니까 에러가 많았다.

의존성 겹침 에러

일단 의존성이 겹쳐서 생긴 에러가 조금 있다.

부분만 적은 gradle 일부이다.

plugins {
    id 'org.springframework.boot' version '2.5.3'
    id 'io.spring.dependency-management' version '1.0.11.RELEASE'
}

dependencies {
    implementation (
            'org.springframework.boot:spring-boot-starter-web', //이부분
            'org.springframework.boot:spring-boot-starter-test', //이부분
            'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.2.0',
            'org.mariadb.jdbc:mariadb-java-client', //이부분
            'commons-io:commons-io:2.6',
            'commons-fileupload:commons-fileupload:1.3.3',
            'javax.servlet:jstl',
            'org.projectlombok:lombok',
    )
}

이렇게 주석처리한 부분들이 에러를 띄웠다.

각자의 버전마다 호응(?)이 되는 버전들이 맞아야 세팅이 완료가 되는데 서로 충돌해서 발생하는 에러였다.

그레이들에서

id 'org.springframework.boot' version '2.5.3'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'

이 두가지의 부분이 중요한데,

org.springframework.boot는 부트 버전을 명시하여 boot starter 관련 된것들을 통일 시켜주고

dependency-management는 다른 라이브러리들의 의존성을 관리해주는 것인데 최적화된 버전들을 맞춰주는 역할을 한다.

그러면서 버전이 맞지않는게 생기면 에러를 띄워준다.

톰캣 오류

그리고 tomcat 오류였다.

부트와 jsp는 잘 맞지않는다.

그럼에도 일단 jsp가 너무 많아서 일단 jsp를 사용하려고 했기 때문에

의존성에는

implementation (
    'javax.servlet:jstl',
    'org.apache.tomcat.embed:tomcat-embed-jasper'
)

두가지를 일단 추가 해줬다. JSP를 사용하려면 embed-jasper가 존재해야 하는데

이건 기본으로 작성해줘서 문제가 아니었다. 😰

application.properties

spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp

여기는 둘다 잘 해주었는데.. 왜문제일까 약 2시간 고민했다 😡

근데 여기가 문제였다...

스크린샷 2021-08-21 오후 5 45 32

Working Directory에 저 설정을 안해주면 jsp 파일을 안찾는다. 그냥 반응이 없음..

@Controller @RequestMapping 이런건 문제가 아니었다.

Bean 주입

Bean을 예를 들어

public interface TestInter {
    void hello();
}

@Repository
public class TestImpl implements TestInter {
    @Override
    public void hello() {
        System.out.println("hello");
    }
}

@RequiredArgsConstructor
public class TestService {
    private final TestInter testInter;
}

스프링5 프로그래밍 입문

여기서 봤던건데 스터디원 한분이 알려줬다. 그러면서 책에있는게 기억이 나더라...

결론은 빈을 뭘 주입해야할지 모르는것이다.
@Qualifier를 통해 명시해줘서 하거나 이전 회사에서 하던 방식으로 어노테이션 뒤에 (빈 이름) 해서 매칭해주는 식으로 해야한다. 이게 좋지 않아서 다 삭제했다.

스크린샷 2021-08-21 오후 5 54 26

이랬던 구조들을

스크린샷 2021-08-21 오후 5 54 42

이렇게 바꾸었다. 클래스 이름들은 추후 안정화가 되면 바꿀 계획이다.

학원에서부터 벗어난지 꽤됐고, 그러면서 TDD강의까지 듣고있고 그동안 공부했던거를 생각하면서 코드를 보니까
더러운 부분이 참많다.

이제 시작이고 끝을 보겠다. 계속 리팩토링 하는 과정을 블로그 + 깃허브 에 업데이트 할 것이다.

728x90

'Spring' 카테고리의 다른 글

Filter, Interceptor 정리  (0) 2022.08.07
Jasypt  (0) 2022.08.07
Spring Data JPA  (0) 2022.08.06
Spring -> Spring Boot 마이그레이션  (0) 2022.08.05

+ Recent posts