반응형

스프링 시큐리티와 앵귤러JS - Spring Security and AngularJS


Part I : 단일 페이지 보안 어플리케이션 (A Secure Single Page Application)

Part II: 로그인페이지 (The Login Page)

Part III: 리소스 서버 (The Resource Server)

Part IV: API 게이트웨이 (The API Gateway)

Part V: OAuth2와 싱글사인온 (Single Sign On with OAuth2)

Part VI: 다중 UI 어플리케이션과 게이트웨이 (Multiple UI Applications and a Gateway)

Part VII: 모듈화한 AngularJS 어플리케이션  (Modular AngularJS Application)

Part VIII: Angular 어플리케이션 테스트 (Testing an Angular Application)


--------------------------------------------------------------------------------

단일페이지 보안어플리케이션 A Secure Single Page Application

이 섹션에서 스프링 시큐리티, 스프링 부트와 앵귤러JS의 멋진 기능을 같이 조합하여 쾌적하고 시큐어한 사용자 경험을 제공하려고 한다. 스프링과 앵귤러JS를 막 시작하려는 사람도 충분히 따라할수 있는 수준이지만, 많은 디테일한 정보를 제공하여 경력자들 또한 이롭게 할 것이다. 이 글은 스프링 시큐리티와 앵귤러JS의 새 기능을 순차적으로 연재하는 시리즈의 첫번째 섹션이다. 연재가 되면서 어플리케이션을 차츰 더 낫게 손보겠지만 이후의 주요 변화는 기능적인 것보다는 아키텍쳐 관점이 될 것이다.


스프링과 단일페이지 어플리케이션 Spring and the Single Page Application

HTML5과 "단일페이지어플리케이션"은 요즘 개발자들에게 극도의 가치가 있는 툴이지만 정적인 컨텐츠(HTML,CSS와 자바스크립트)뿐만 아니라 의미가 되는 상호작용은 백엔드서버에 들어있으므로 우리는 백엔드 서버가 필요하다. 백엔드서버는 모든 역할의 갯수 - 정적인 컨텐츠를 제공하고, 가끔 (요즘엔 많지않지만) 동적인 HTML를 랜더링하며, 보호하는 자원의 안전한 접근을 보장하며, 자바스크립트와 브라우저내에서 HTTP와 JSON을 통해 상호작동 (REST API라 언급되기도함)을 하는 - 만큼의 역할을 할 수 있다.

스프링은 백엔드 기능(특히 엔터프라이즈 환경에서)을 만드는데 있어 언제나 인기있는 기술이었고,  스프링 부트의 출현과 함께 이러한 기능을 제공하기에 이보다 더 쉬울 순 없게 되었다. 오직 스프링부트와 앵귤러JS 그리고 트위터 부트스트랩만 사용해서 어떻게 새 단일페이지 어플리케이션을 살펴보도록 하자. 이 기술세트를 선택하게 된 특별한 이유가 있는건 아니고 그냥 엔터프라이즈 자바 바닥에서 아주 인기가 많기 때문에, 이렇게 시작할 충분한 가치가 있기 때문이다. 


새 프로젝트 만들기 Create a New Project

이 어플리케이션을 만들기위한 단계마다 스프링과 앵귤러에 익숙하지않은 사람들이 어떻게 되어가는지 따라올 수 있게 약간의 부연설명을 덧붙일 것이다. 부연설명이 필요없는 사람들은 이 단락을 넘기고 어플리케이션을 동작하는 마지막 섹션으로 바로 가도 된다. 새 프로젝트를 생성할 수 있는 몇가지 옵션들이 있다:


우리가 빌드할 완성된 프로젝트의 소스코드는 여기 Github에서 볼 수 있다. 필요하다면 프로젝트를 클론하여 돌려보고 바로 다음 단계로 건너뛰어도 된다.


Spring Tool Suite 이용하기

Spring Tool Suite (이클립스 플러그인의 한종류)의 메뉴 File->New->Spring Starter Project에서 프로젝트를 만들거나 불러올 수 있다.


홈페이지 추가하기 Add a Home Page

단일페이지 어플리케이션의 핵심은 하나의 정적인 "index.html"이다. 바로 프로젝트의 "src/main/resources/static" 또는 "src/main/resources/public"의 경로에 다음과 같이 하나 만들어보자:

index.html
<!doctype html>
<html>
<head>
<title>Hello AngularJS</title>
<link href="css/angular-bootstrap.css" rel="stylesheet">
<style type="text/css">
[ng\:cloak], [ng-cloak], .ng-cloak {
  display: none !important;
}
</style>
</head>

<body ng-app="hello">
  <div class="container">
    <h1>Greeting</h1>
    <div ng-controller="home" ng-cloak class="ng-cloak">
      <p>The ID is {{greeting.id}}</p>
      <p>The content is {{greeting.content}}</p>
    </div>
  </div>
  <script src="js/angular-bootstrap.js" type="text/javascript"></script>
  <script src="js/hello.js"></script>
</body>
</html>

단지 "Hello World"를 출력하는 코드이므로 매우 간결하고 쉽다.


홈페이지의 특징 Features of the Home Page

이 홈페이지의 가장 주요한 기능은 다음과 같다:

  • <head>에서 CSS를 불러온다. 하나의 엘리먼트에는 실제로 아직 존재하지는 않지만 ("angular-bootstrap.css")와 같이 임시적으로 파일 이름을 채우며, 인라인 스타일시트가 "ng-cloak" 클래스를 정의 하고 있다.

  • "ng-cloak" 클래스는 <div> 컨탠트에 적용되어 해당 동적 컨텐트를 앵귤러JS가 처리할때까지 보지않게(hidden) 한다 - 초기 페이지 로딩중에 페이지가 깜빡거리는 현상을 막기 위해서다.

  • <body>에 마크된 ng-app="hello"는 앵귤러가 "hello"라 불리는 어플리케이션을 인식할 수 있게 만들어주는 하는 자바스크립트 모듈을 정의해야 한다는 의미다.

  • "ng-cloak"을 제외한 모든 CSS 클래스는 트위터 부트스트랩에서 불러온다. 스타일시트를 올바르게 설정해두면 페이지를 이쁘게 만들어줄것이다.

  • greeting안의 컨탠트는 {{greeting.content}}와 같이 핸들바를 이용하여 마크업되었다. 이것은 후에 앵귤러에 의해 실제 값으로 채워질 것이다. (<div>)로 둘러쌓인 ng-controller directive에 의해 "home" 이라 불리는 controller에 의해). 

  • 앵귤러JS (와 트위터 부트스트랩)은 <body>의 하단에 포함되어 브라우저가 모든 HTML을 처리한 이후 읽혀질것이다.

  • 또한 어플리케이션의 행동을 정의해둘 별도의 "hello.js"이 있다. 

곧 스크립트와 스타일시트 파일들을 만들테니 지금은 그들이 없는 파일이라는걸 무시하기로 하자.


어플리케이션 동작하기 Running the Application

일단 홈페이지 파일이 추가되면 (아직 많은 것 하지않았음에도 불구하고) 어플리케이션을 브라우저에서 실행할 수 있다. 커맨드라인상에 다음과 같이 타입해보자:

$ mvn spring-boot:run

그리고 브라우저를 열고 주소창에 http://localhost:8080를 타입한다. 홈페이지가 실행되면 브라우저 팝업창이 뜨며 아이디와 패스워드를 물어볼것이다. (아이디는 "user"이고 패스워드는 어플리케이션 시작시 콘솔로그에 출력된다). 아직 컨탠트가 없지만 인증에 성공하면 "greeting"헤더를 가지는 빈페이지를 볼 수 있을 것이다.

 패스워드 확인을 위해 콘솔창을 찾는게 싫다면 프로젝트의 "src/main/resources"의 위치에 application.properties 파일을 만들어 다음과 같이 추가하면된다: security.user.password=password (패스워드는 원하는대로 변경가능하다). "application.yml"파일을 만들어 넣어도 똑같이 동작한다.

IDE에선 그냥 어클리케이션 클래스의 main() 메소드를 실행하면 된다. 지금은 UiApplication이라는 하나의 클래스만 있다.

패키지 빌드하여 standalone JAR을 만들어 다음과 같이 실행해도 된다:

$ mvn package
$ java -jar target/*.jar

프론트엔드 에셋 Front End Assets

앵귤러JS나 다른 프론트엔드 기술의 초급 튜토리얼들은 주로 라이브러리 에셋을 직접 라이브러리와 연관된 여러개의 파일들을 다운받아 리소스 경로에 직접 넣는 것 대신 인터텟을 통해 바로 가져오라고 가르친다. (이를테면 앵귤러 JS 웹사이트에서는 Google CDN를 통해 다운받는것을 추천한다). 이것은 어플리케이션을 동작하는데 반드시 따라야하는 것은 아니지만 실제 제품화 단계에서 브라우저와 서버같의 불필요한 통신을 피할수 있는 최고의 실전 팁이다. 우리가 CSS 스타일시트를 변경하거나 커스터마이즈하지 않는다면 "angular-bootstrap.css"파일을 프로젝트에 만들어두는 것도 불필요하므로 Google CDN를 통해 정적인 에셋을 사용하면 된다. 하지만 실제 어플리케이션은 거의 대부분 스타일시트를 수정하면서도 CSS소스 자체에는 손대고 싶지않기 때문에 Less 나 Sass와 같은 상위레벨의 툴을 사용한다. 따라서 우리 또한 그렇게 해볼 것이다.

이것을 위한 많은 방법들이 있지만 이 섹션의 목적을 위해 우리는 자바기반의 프론트엔드 에센의 선처리 및 패키징 툴체인인 wro4j을 사용할 것이다. 그냥  서블릿 어플리케이션에서 JIT (Just in Time) Filter로서 사용할 수 있지만 메이븐이나 이클립스와 같은 빌드툴을 또한 매우 잘 지원한다. 그리고 우리가 이것을 쓰려는 이유다. 따라서 우리는 정적 리소스 파일들을 빌드하여 번들화시켜 우리의 어플리케이션 JAR에 넣을 것이다.

여담: Wro4j 는 아마도 하드코어 프론트엔드 개발자가 선택할 만한 툴은 아닐것이다. 그들은 통상 bower 와/또는 grunt와 같은 노드기반의 툴체인을 쓴다. 그러한 툴은 명백하게 아주 훌륭하고 인터넷상에 수많은 튜토리얼을 구할수 있다. 당신이 그것을 선호한다면 이 프로젝트내에서 자유롭게 쓰길 바란다. 그냥 프로젝트의 "src/main/resources/static" 경로에 그 툴체인으로 만들어진 결과파일/폴더를 넣으면 바로 잘 동작할것이다. 당신이 하드코어 프론트엔드 개발자가 아니라면 이 자바기반의 툴인 wro4j를 나름 편하게 활용할 수 있을 것이다.

빌드타임에 정적 리소스를 만드려면 메이븐 pom.xml에 약간의 마법을 뿌려야한다. (좀 장황하지만 boilerplate로서 메이븐의 parent pom안에서 또는 그래들의 shared task나 plugin으로 추출된다):

pom.xml

<build>
  <resources>
    <resource>
      <directory>${project.basedir}/src/main/resources</directory>
    </resource>
    <resource>
      <directory>${project.build.directory}/generated-resources</directory>
    </resource>
  </resources>
  <plugins>
    <plugin>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-maven-plugin</artifactId>
    </plugin>
    <plugin>
      <artifactId>maven-resources-plugin</artifactId>
      <executions>
        <execution>
          <!-- Serves *only* to filter the wro.xml so it can get an absolute
            path for the project -->
          <id>copy-resources</id>
          <phase>validate</phase>
          <goals>
            <goal>copy-resources</goal>
          </goals>
          <configuration>
            <outputDirectory>${basedir}/target/wro</outputDirectory>
            <resources>
              <resource>
                <directory>src/main/wro</directory>
                <filtering>true</filtering>
              </resource>
            </resources>
          </configuration>
        </execution>
      </executions>
    </plugin>
    <plugin>
      <groupId>ro.isdc.wro4j</groupId>
      <artifactId>wro4j-maven-plugin</artifactId>
      <version>1.7.6</version>
      <executions>
        <execution>
          <phase>generate-resources</phase>
          <goals>
            <goal>run</goal>
          </goals>
        </execution>
      </executions>
      <configuration>
        <wroManagerFactory>ro.isdc.wro.maven.plugin.manager.factory.ConfigurableWroManagerFactory</wroManagerFactory>
        <cssDestinationFolder>${project.build.directory}/generated-resources/static/css</cssDestinationFolder>
        <jsDestinationFolder>${project.build.directory}/generated-resources/static/js</jsDestinationFolder>
        <wroFile>${project.build.directory}/wro/wro.xml</wroFile>
        <extraConfigFile>${basedir}/src/main/wro/wro.properties</extraConfigFile>
        <contextFolder>${basedir}/src/main/wro</contextFolder>
      </configuration>
      <dependencies>
        <dependency>
          <groupId>org.webjars</groupId>
          <artifactId>jquery</artifactId>
          <version>2.1.1</version>
        </dependency>
        <dependency>
          <groupId>org.webjars</groupId>
          <artifactId>angularjs</artifactId>
          <version>1.3.8</version>
        </dependency>
        <dependency>
          <groupId>org.webjars</groupId>
          <artifactId>bootstrap</artifactId>
          <version>3.2.0</version>
        </dependency>
      </dependencies>
    </plugin>
  </plugins>
</build>

위의 소스 그대로 당신의 POM에 붙여넣거나 Github에 있는 소스를 가져다 쓰면된다.

주요 사항은:

  • 우리는 (CSS와 스타일링을 위한 jquery와 부트스트랩, 그리고 비지니스 로직을 위한 앵귤러JS의) 의존성으로서 몇몇 webjars 라이브러리를 추가했다. 이러한 jar 파일안의 정적 리소스들의 일부는 우리가 만든 angular-bootstarp.* 같은 파일들을 포함할 것이다. 그러나 jar 자체는 어플리케이션에 같이 패키지 될 필요없다.

  • 트위터 부트스트랩은 JQuery에 의존성을 가지므로 같이 넣을 것이다. 부트스트랩을 쓸 필요없는 앵귤러JS 어플리케이션은 이것이 필요없다. 왜냐하면 앵귤러는 자체적으로 JQuery로 쓰려는 기능을 가지고 있기때문이다.

  • <resources/> 섹션에서 선언되었기 때문에 생성된 리소스들은 "target/generated-resources"폴더에 위치되며, 프로젝트를 빌드한 JAR안에 패키지될 것이다. (이클립스 m2e같은 메이븐 툴링을 쓴다는 가정하에) IDE에서는 클래스패스를 통해 쓸 수 있다.

  • wro4j-maven-plugin은 약간 이플립스 통합기능을 가지고 있어 이클립스 마켓플레이스에서 인스톨할 수 있다. (어플리케이션이 완성되면 필요없으므로 처음이면 나중에 인스톨하라). 인스톨하면 이클립스는 이후 리소스 파일들을 주시하고 변경사항이 있으면 결과물을 자동으로 재생성한다. 디버그 모드로 동작중이라면 브라우저에 변경사항을 즉시 반영한다.

  • Wro4j는 당신의 빌드 클래스패스를 알지 못하는 XML설정을 통해 제어하며 오직 파일의 절대경로만 인식한다. 그러므로 우리는 파일의 절대 경로를 만들어 wro.xml에 추가해야한다. 이것을 위해 메이븐 리소스 필터링을 사용할 것이며 이것이 왜 명시적으로 "maven-resources-plugin" 선언을 해줘야 하는가에 대한 이유다.

필요한 POM 수정은 이게 전부이며 "src/main/wro"에 위치할 wro4j 빌드파일을 추가할일만 남았다.


Wroj4j 소스파일들 Wro4j Source Files

Github의 소스파일엔 오직 3개 파일만 볼 수 있다. (그중 차후 커스터마이징을 위해 하나는 빈파일이다)

  • wro.properties는 wro4j 엔진의 선처리preprocessing와 랜더링을 위한 설정configuration 파일이다. 이 설정파일로 이 툴체인의 다양한 기능을 켜거나 끌수있다. Less로 부터 CSS를 컴파일하고 자바스크립트를 minify하려는 우리의 경우, 결과적으로 필요한 모든 라이브러리들의 소스를 섞어 2개의 파일로 합칠것이다.

    wro.properties
    preProcessors=lessCssImport
    postProcessors=less4j,jsMin
  • wro.xml는 "angular-bootstarp"이라는 단일 "그룹"을 선언하며 생성되는 정적 리소스의 기본명으로 종료한다. 우리가 추가한 webjars의 <css> 와 <js> 엘리먼트의 참조형 및 로컬 리소스파일인 main.less를 또한 포함하고있다.

    wro.xml
    <groups xmlns="http://www.isdc.ro/wro">
      <group name="angular-bootstrap">
      <css>webjar:bootstrap/3.2.0/less/bootstrap.less</css>
        <css>file:${project.basedir}/src/main/wro/main.less</css>
        <js>webjar:jquery/2.1.1/jquery.min.js</js>
        <js>webjar:angularjs/1.3.8/angular.min.js</js>
      </group>
    </groups>
  • main.less는 예제코드로서 빈 파일이지만 UI의 Look & Feel이나 트위터 부트스트랩의 (밑의 한줄로) 기본 파란색을 옅은 핑크색으로 바꾸는 등의 기본설정을 바꾸거나, 커스터마이즈하는데 사용된다.

    main.less
    @brand-primary: #de8579;
  • 위의 파일들을 프로젝트로 복사해넣고 "mvn package"를 타입하면 JAR파일안에 "bootstarp-angular.*" 리소스 파일들을 볼 수 있을 것이다. 이제 앱을 실행하면, CSS가 작동하는것을 확인할수 있다. 하지만 아직 비지니스 로직과 페이지 이동기능이 여전히 빠져있다.


    앵귤러 어플리케이션 만들기 Create the Angular Application

    이제 "hello" 어플리케이션을 만들어보자 ("src/main/resources/static/js/hello.js" 경로에 만들어야 "index.html"의 하단의 <script/> 엘리먼트가 올바른 경로를 찾을수 있다)

    최소사양의 앵귤러JS 어플리케이션은 다음과 같다.

    hello.js
    angular.module('hello', [])
      .controller('home', function($scope) {
        $scope.greeting = {id: 'xxx', content: 'Hello World!'}
    })

    어플리케이션의 이름은 "hello"이고 빈 "config" 와 "home"이라는 이름의 "controller"를 가지고 있다. "home" controller는 "index.html"에 ng-controller="home"을 선언한 <div> 컨텐트때문에 "index.html"가 로드될때  같이 호출된다

    controller 함수안에 마법과도 같은 $scope을 주입했고 (앵귤러는 명명규칙naming convention에 따른 의존성주입 dependency injection by naming convention을 한다), 당신의 함수변수의 이름을 인식하고 있다는걸 명심하자. $scope은 컨트롤러가 책임지는 함수내에서 UI엘리먼트를 위한 컨텐트와 행동규약등을 설정해준다.

    당신이 이 파일을 "src/main/resources/static/js" 경로밑에 추가했다면 어플리케이션은 이제 안전하고 기능적이되었으며 "Hello World!"를 보여줄것이다. greeting은 HTML내에{{greeting.id}} 와 {{greeting.content}} 와 같은 placeholder들은 핸들바를 사용하는 앵귤러에 의해 랜더되었다. 


    동적 컨텐트 추가하기 Adding Dynamic Content

    지금까지 우리는 하드코드된 greeting을 가진 어플리케이션을 만들었다. 어떻게 서로가 맞추어가는지 배우면 유용할것이다. 그러나 실제로 우리가 기대한 컨텐트는 서버로부터 오는것이므로 이제 HTML endpoint를 만들어 greeting을 받아올 것이다. "src/main/java/demo"에 있는 어플리케이션의 메인클래스에  @RestController 어노테이션과 새 @RequestMapping을 정의하자:

    UiApplication.java
    @SpringBootApplication
    @RestController
    public class UiApplication {
    
      @RequestMapping("/resource")
      public Map<String,Object> home() {
        Map<String,Object> model = new HashMap<String,Object>();
        model.put("id", UUID.randomUUID().toString());
        model.put("content", "Hello World");
        return model;
      }
    
      public static void main(String[] args) {
        SpringApplication.run(UiApplication.class, args);
      }
    
    }

    새프로젝트를 어떻게 만들었냐에 따라 UiApplication이 아닐 수도 있 다. @SpringBootApplication 대신 @EnableAutoConfiguration @ComponentScan @Configuration이 있을 수도 있다.

    어플리케이션을 실행하고 curl에서 "/resource" endpoint를 타입해보면 기본적으로 보안이 작동하여 다음과 같은 메세지를 볼 수 있다:

    $ curl localhost:8080/resource
    {"timestamp":1420442772928,"status":401,"error":"Unauthorized","message":"Full authentication is required to access this resource","path":"/resource"}

    앵귤러에서 동적리소스 불러오기 Loading a Dynamic Resource from Angular

    이제 브라우저에서 메세지를 받아봐보자. "home" controller를 XHR을 사용하여 보호된 리소스를 불러올수있게 수정하자:

    hello.js
    angular.module('hello', [])
      .controller('home', function($scope, $http) {
      $http.get('/resource/').success(function(data) {
        $scope.greeting = data;
      })
    });

    core기능으로 앵귤러가 제공해주는 $http서비스를 주입하고 GET메소드로 resource에 접근한다. 성공적으로 요청되면 앵귤러는 콜백으로 Response body로부터 JSON 타입을 돌려받는다.

    다시 어플리케이션을 실행하면 (또는 그냥 브라우저의 홈페이지를 다시 로드하면) Unique ID를 가진 동적 메세지를 볼수 있을것이다. 리소스가 보호된 상태라 직접적으로 curl을 사용할 순 없지만 브라우저는 컨텐트에 접근할 수 있다. 우리 이제 백줄도 안되는 코드로 단일페이지 보안 어플리케이션을 가지게 되었다!

    당신은 아마 파일 수정후 브라우저에 정적 리소스의 재실행을 강제하고 싶을 수 있다. 크롬(파이어폭스에선 플러그인을 통해)에서 "developer tools" 메뉴 (단축키 F12)를 통해 가능하며 또는 CTRL+F5를 사용하면 된다.


    어떻게 작동하는가? How Does it Work?

    브라우저와 백엔드간의 연동은 사용자의 브라우저에서 확인할 수 있다. 만일 사용자가 개발자 툴을 사용한다면 (보통 크롬에서는 기본값으로 F12를 누르면 열리고 파이어폭스에서는 플러그인을 설치해야할 것이다) 정리하자면:

    VerbPathStatusResponse

    GET

    /

    401

    인증을 위한 브라우저 팝업 프롬프트

    GET

    /

    200

    index.html

    GET

    /css/angular-bootstrap.css

    200

    트위터 부트스트랩 CSS

    GET

    /js/angular-bootstrap.js

    200

    부트스트랩과 앵귤러JS

    GET

    /js/hello.js

    200

    어플리케이션 로직

    GET

    /resource

    200

    JSON greeting

    브라우저가 단일 연동으로서 홈페이지를 로드한다고 간주하기때문에 사용자는 아마 401 응답을 볼 수 없을것이다. 그리고 /resource를 위한 두번의 요청을 볼수 있는데, 이는 CORS negotiation때문이다.

    요청들을 더 자세히 들여다 보면, 모든 요청에 다음과 같은 "인증Authorization"헤더가 있는 것을 볼 수 있다:

    Authorization: Basic dXNlcjpwYXNzd29yZA==

    브라우저는 모든 요청에 사용자명과 패스워드를 보내고 있는데 ( 그러므로 제품화단계에선 HTTPS으로만 써야하는걸 기억하자). 이런한 단계는 "앵귤러"와 무관하므로 사용자가 자바스크립트 프레임워크를 쓰던 안쓰던 잘 동작한다.


    무엇이 문제인가? What’s Wrong with That?

    표면적으로는 매우 잘 작동하는 것처럼 보인다. 간결하고 구현이 간단하며, 모든 데이터는 패스워드에 의해 안전하다. 그리고 사용자가 프로트엔드 또는 백엔드 기술세트를 바꾸더라도 여전히 잘 작동할 것이다. 하지만 약간의 이슈가 있는데:

    • 기본 인증은 사용자명과 패스워드 인증으로 제한되어있다.

    • 인증 UI는 흔하지만 매우 추하다 ( 브라우저 다이얼로그).

    • Cross Site Request Forgery (CSRF)로부터 보호되지않는다.

    CSRF는 실제로 백엔드 리소스에 GET만 사용하는 지금의 어플리케이션에는 문제가 안될 수도 있다 (예를 들면 서버의 상태변화가 없을때). 일단 사용자가 어플리케이션에 POST, PUT 또는 DELETE 를 사용한다면, 요즘의 기술로는 더 이상 안전하지 않다.

    이 시리즈의 다음 섹션에서, 우리는 HTTP Basic보다 훨씬 유연한 폼 기반의 인증을 사용하도록 어플리케이션을 확장할 것이다. 일단 우리가 폼을 사용하면 CSRF 보호를 할 필요가 있다. 스프링 시큐리티와 앵귤러 둘다 이것을 만드는데 도움을 주는 즉시 활용가능한 멋진 기능들을 가지고 있다. 약간 스포일로해보면, 우리는 HttpSession을 사용할 것이다.

    감사의 말: 이 시리즈를 만드는데 도움을 준 모든분께 감사드리고 싶다. 특히 각각의 섹션과 소스코드를 주의깊게 리뷰를 해주고, 내가 잘 알고 있다고 생각한 부분에서 조차 알지못했던 몇가지 트릭을 알게 해준 Rob Winch 와 Thorsten Spaeth.에게 감사하다.



    반응형

    반응형

    이 가이드는 어떻게 스프링 세션을 스프링 시큐리티와 함께 사용하는지 설명할 것이다. 당신의 어플리케이션에 스프링 시큐리티를 이미 적용했다는 가정하에 진행된다.

    완전한 가이드는 다음의 시큐리티 샘플 어플리케이션링크에서 확인할 수 있다.

    의존성 업데이트 하기 Updating Dependencies

    스프링 세션을 사용하기전, 의존성 업데이트를 해야한다. 메이븐을 쓴다면 다음의 의존성을 추가해주자:

    pom.xml
    <dependencies>
            <!-- ... -->
            <dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session-data-redis</artifactId>
            <version>1.0.2.RELEASE</version>
            <type>pom</type>
            </dependency>
            <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>4.1.6.RELEASE</version>
            </dependency>
    </dependencies>

    스프링 설정 Spring Configuration

    필수 의존성을 추가하면 스프링 설정을 생성할 수 있다. 스프링 설정으로 Servlet 필터를 만들어 HttpSession 구현체를 스프링 세션의 엄호하에 사용되는 구현체로 바꿔줘야한다. 다음의 스프링 설정을 추가하자:

    @Configuration
    @EnableRedisHttpSession 1
    public class Config {
    
            @Bean
            public JedisConnectionFactory connectionFactory() {
                    return new JedisConnectionFactory(); 2
            }
    }
    1@EnableRedisHttpSession 어노테이션은 Filter를 구현한 springSessionRepositoryFilter라는 이름의 스프링 빈을 만들어준다. 이 필터는 HttpSession를 스프링 세션의 엄호하에 사용되는 구현체로 대체해준다. 이 인스턴스에서 스프링 세션은 레디스에 엄호하에 있다.
    2

    스프링 세션을 레디스 서버에 연결하는 RedisConnectionFactory를 만들었다.RedisConnectionFactory that connects Spring Session to the Redis Server. 기본포트인 6379로 연결하도록 설정한다. 스프링 데이터 레디스의 자세한 설정정보는 레퍼런스 문서를 참고하자.

    서블릿 컨테이너 초기화 Servlet Container Initialization

    우리는 스프링 설정으로 Filter를 구현한 springSessionRepositoryFilter라는 이름의 스프링 빈을 만들어 스프링 세션에 엄호하에 사용되는 커스텀 구현체로 HttpSession을 대체하는데 쓴다.

    우리의 Filter를 동작하게 하기 위해, 스프링은 우리가 설정한 Config 클래스를 불러와야한다. 어플리케이션이 이미 스프링 설정을 SecurityInitializer 클래스를 통해 실행되고 있기때문에 간단히 다음의 Config 클래스를 추가해주면된다:

    src/main/java/sample/SecurityInitializer.java
    public class SecurityInitializer extends
                    AbstractSecurityWebApplicationInitializer {
    
            public SecurityInitializer() {
                    super(SecurityConfig.class, Config.class);
            }
    }

    마지막으로 서블릿 컨테이너 (톰캣같은)가 모든 요청에 우리의springSessionRepositoryFilter 를 사용하게 만들야한다. 스프링세션의 springSessionRepositoryFilter가 스프링 시큐리티의 springSecurityFilterChain이 불러지기전에 호출되어야한다는 것은 극도로 중요하다. 스프링 시큐리티에서 사용하는 HttpSession은 반드시 스프링 세션의 엄호하에 있어야 한다. 다행스럽게도 스프링 세션은 이것을 극도로 쉽게 만들어주는 AbstractHttpSessionApplicationInitializer 이라는 유틸리티 클래스를 제공해준다. 밑의 예제를 보자:

    src/main/java/sample/Initializer.java
    public class Initializer extends AbstractHttpSessionApplicationInitializer {
    
    }

    클래스 이름 (Initializer)은 무엇이되도 상관없다. 중요한 것은 우리가 AbstractHttpSessionApplicationInitializer를 확장했다는 것이다.

    AbstractHttpSessionApplicationInitializer 를 확장함으로서, springSessionRepositoryFilter라는 이름의 스프링 빈이 스프링 시큐리티의 Security’sspringSecurityFilterChain이전에 모든 요청을 처리하도록 서블릿 컨테이너와 함께 등록될 것이다.

    시큐리티 샘플 어플리케이션 security Sample Application

    시큐리티 샘플 어플리케이션 실행하기 Running the security Sample Application

    소스 코드를 받아서 다음의 명령어를 호출함으로서 샘플을 실행할 수 있다:

    샘플을 동작하려면 먼저 localhost에 레디스 2.8 또는 그 이후버전을 인스톨하고 기본 포트(6379)로 실행하자. 설치 설정이 다르면 JedisConnectionFactory에 레디스 서버를 해주면 된다.

    $ ./gradlew :samples:security:tomcatRun

    이제 http://localhost:8080/를 통해 어플리케이션에 접근할 수 있다.

    시큐리티 샘플 어플리케이션 둘러보기 Exploring the security Sample Application

    어플리케이션을 사용해보자. 다음의 로그인 정보를 입력하자:

    • Username user

    • Password password

    Login 버튼을 누르면, 방금 입력한 사용자로 로그인됬다로 알려주는 메세지를 볼수 있다. 이 사용자 정보는 톰캣의 HttpSession 구현체가 아닌 레디스에 저장되어있다.

    어떻게 동작하는가? How does it work?

    톰캣의 HttpSession대신, 우리는 실제 레디스에 값을 저장하고 있다. 스프링 세션은 레디스의 엄호하에 있는 구현체로 HttpSession을 대체한다. 스프링 시큐리티의SecurityContextPersistenceFilter SecurityContextHttpSession 에 저장할때, 이는 레디스안에 저장된다.

    새로운 HttpSession이 만들어질때, 스프링 세션은 사용자의 브라우저에 사용자의 세션ID를 가지고 있는 SESSION이라는 쿠키를 만든다. 계속 진행해서 쿠키를 둘러보자. (크롬이나 파이어폭스에서 쿠키값을 확인해볼수 있다)

    redis-cli를 쓰면 세션값을 언제든지 레디스에서 손쉽게 삭제할 수 있다.예를 들면 리눅스 기반의 시스템에서는 다음과 같이 타입하면된다:

    $ redis-cli keys '*' | xargs redis-cli del
     redis-cli 설치는 레디스 문서를 참고하자.

    또는, 명시적인 키explicit key값을 삭제해도 된다. 7e8383a4-082c-4ffe-a4bc-c40fd3363c5e의 값을 가지는 세션 쿠키를 삭제하려면 다음을 터미널에 타입하자:

    $ redis-cli del spring:session:sessions:7e8383a4-082c-4ffe-a4bc-c40fd3363c5e

    이제 다시 http://localhost:8080/ 를 방문해보면 더이상 인증되어있지 않은 걸 확인할 수 있다.


    반응형

    반응형

    스프링 부트 1.3.0 릴리즈 노트 - 2015년 11월 17일

    원문: https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-1.3-Release-Notes

    스프링부트 1.2이후 업그레이드된 것

    스프링 부트 1.2에서 제거된것 Deprecations from Spring Boot 1.2

    스프링 부트 1.2에서 디프리케이트된 클래스, 메소드, 프로퍼티들은 이번 릴리즈에서 제거되었다.업그레이드에 앞서 디프리케이트된 메소드를 호출하는지 먼저 확인해야한다.


    잭슨 Jackson

    스프링 부터 1.2는 어플리케이션 컨텍스트내에 모든 ObjectMapper 를 가지는 잭슨 모듈에 등록했다. 이는 ObjectMapper bean의 모듈을 완전히 제어할수 없게 만들었기 때문에, 스프링 부트 1.3에서는 오직 자동설정된 Jackson2ObjectMapperBuilder.와 함께 설정되거나 생성된 ObjectMappers 만 잭슨 모듈 빈으로 등록된다. 이는 모듈설정의 방식을 스프링부트의 다른 잭슨설정과 똑같이 만들어줬다.


    로깅 Logging

    스프링 특화 설정 Spring specific configuration

    스프잉 특화 로그 설정파일의 중복 초기화를 막기위해 기본 로그 설정의 이름을 -spring 접두사를 붙여쓰도록 바꿔주는것을  (필수요구사항은 아니지만) 권장한다. 예를 들면, logback.xml 파일을 logback-spring.xml로 바꾸는 것이다.


    초기화 실패 Initialization failures

    스프링 부트 1.2에선 logging.config 를 써서 로깅 설정파일을 커스터마이즈할 수 있었다. 파일이 존재하지않으면 기본설정을 사용해서 조용히 대비할 수 있었다. 스프링 부트 1.3는 파일이 없을경우 실패하게 된다. 유사하게, 사용자가 잘못 설정된 커스텀 로그백 설정파일을 넣어뒀다면 스프링 부트 1.2는 기본 설정으로 극복할 것이다. 스프링 부트 1.3은 시스템이 에러가 나며(falls) 설정의 문제로  System.err에 리포트된다.


    스프링 HATEOAS Spring HATEOAS

    스프링 HATEOAS 자동설정이 컨텍스트의 기본 ObjectMapper에 영향을 미치지 않도록 재작업되었으므로 spring.hateoas.apply-to-primary-object-mapper 프로퍼티는 삭제되었다. 이는 spring.hateoas.use-hal-as-default-json-media-type 이름의 프로퍼티로 대체되었는데 이는 스프링 HATEOAS HTTP 메세지 컨버터가  application/hal+json요청 뿐만 아니라  application/json의 요청을 처리할 지를 제어하는데 쓰인다.


    /health 종단의 시큐리티 Security for the /health endpoint

    actuator /health endpoint의 어떠한 정보를 보여줄지에 대한 보안 설정은 더 나은 일관성을 가지도록 약간 재조정되었다. 자세한 정보는  HTTP health endpoint access restrictions 를 참고하자.


    HTTP 응답압축 HTTP response compression

    스프링 부트 1.2에서 톰캣사용자를 위한 네이티브 응답 압축 또는 제티, 톰캣, Undertow 사용자를 위한 제티의 GZipFilter 를 사용하는 압축이 지원되었다. 제티팀이 gzip필터를 디프리케이트한데 영감받아 스프링부트 1.3은 이 세 내장 컨테이너에서 네이티브 응답 압축을 지원하도록 변경되었다. 그 결과 server.tomcat.compression. 그리고 spring.http.gzip. 프로퍼티는 더이상 지원하지 않는다. 새로운  server.compression.* 프로퍼티가 대신 사용된다.


    톰캣 세션저장 Tomcat session storage

    기본값으로 톰캣은 더이상 세션 데이터를  /tmp에 저장하지않는다. 사용자가 톰캣과 persistent 세션을 사용하려면 server.session.persistent 프로퍼티를  true로 설정하자. server.session.store-dir 는 특정위치에 파일을 저장할때 쓴다.


    제티 JSP Jetty JSPs

    spring-boot-starter-jetty "Starter POM" 은 더이상 org.eclipse.jetty:jetty-jsp. 을 포함하지않는다. 제티와 JSP를 함께 사용하는 사용자는 스스로 이 의존성을 직접 추가해줘야한다.


    MVC Stacktrace출력 MVC Stacktrace output

    Stacktrace 정보는 이제 스프링 MVC가 에러 응답을 랜더할때 포함되지않는다.스프링 부트 1.2에서 쓰던대로 유지하려면 error.include-stacktrace를 on-trace-param.로 설정하자.


    타임리프의 스프링 시큐리티 통합 Thymeleaf’s Spring Security integration

    스프링 시큐리티 4로의 업그레이드때문에  스프링 1.3은 타임리프의 스프링 시큐리티 지원의 자동설정과 의존성 관리 또한 업그레이드하였다. 새 artiface은 org.thymeleaf.extras:thymeleaf-extras-springsecurity4.이다 pom.xml 또는 build.gradle 를 각각 업그레이드 해줘야한다.


    /template폴더가 없을때 나는 에러 Missing /templates folder errors

    스프링 부트 어플리케이션은  /templates 폴더가 없다고 시작에 실패하지않는다. 스프링 부트에서 지원되는 템플릿 기술을 사용중인데 /templates 폴더를 추가하지 않았다면 이제 warning으로 로그될것이다.


    그루비 템플릿 Groovy templating

    GroovyTemplateProperties 는 이제 AbstractTemplateViewResolverProperties 를 확장하여 추가적인 설정옵션을 제공한다. 사용자가 현재 커스텀 리소스 위치를 정의하기위해 prefix.spring.groovy.template.prefix 프로터리를 설정해두었다면,  prefix.spring.groovy.resource-loader-location로 이름을 바꿔줘야 한다.


    그래들 플러그인 Gradle plugin


    bootRun 리소스 bootRun resources

    스프링 부트 그래들 플러그인은 bootRun를 쓸때 클래스패스에 src/main/resources 를 직접 추가하지않는다. 만일 사용자가 실시간 즉시 편집을 원하면, Devtools 를 쓰는것을 권장한다. 스프링 부트 1.2에서 했던대로 되돌리려면 addResources 프로퍼티는 그래들 빌드에 설정할 수 있다.


    의존성 관리 Dependency management

    스프링의 그래들 플러그인이 이번 릴리즈에서 dependency management plugin를 사용할 수 있게 업데이트되었다. 대부분의 사용자는 이 변화에 무관하지만 자신이 설정한 버전을 적용하려는  versionManagement 설정을 사용하는 사용자들은 그들의  빌드 스크립트를 업그레이드해야한다.

    버전관리를 설정하기위해 프로퍼티파일을 요구하는 대신, 새로운 플러그인이 사용자가 메이븐 bom을 쓸수있도록 해준다. 예를 들면:

    dependencyManagement {
        imports {
            mavenBom 'com.example:example-bom:1.0'
        }
    } 

    어플리케이션 플러그인 Application plugin

    스프링 부트 그래들 플러그인은 더이상 그래들의  application plugin 을 기본으로 적용하지않는다. 만일 이 어플리케이션 플러그인을 쓰려면, build.gradle.에 사용자가 적용해줘야한다.

    어플리케이션 플러그인이 제공하는 기능이 필요없지만  mainClassName 나 applicationDefaultJvmArgs 프로퍼티를 쓰고싶으면 build.gradle.에 작은 업데이트만 해주면 된다.

    메인클래스는 이제 springBoot extension의 mainClass 프로퍼티로 설정가능해졌다. 예를들면:

    springBoot { mainClass = 'com.example.YourApplication' }

    applicationDefaultJvmArgs 는 사용자 프로젝트의 ext block에서 설정할 수 있다. 예를들면:

    ext {
        applicationDefaultJvmArgs = [ '-Dcom.example.property=true' ]
    }

    어플리케이션 플러그인의 run task에 있는 main 프로퍼티를 사용해서 사용자 프로젝트의 메인클래스를 설정하려면 다음의 설정을  bootRun task에 대신 설정해 줘야한다:

    bootRun {
        main = com.example.YourApplication
    }

    메이븐 플러그인 Maven plugin

    spring-boot:run 리소스 spring-boot:run resources

    스프링 부트 메이븐 플러그인은  spring-boot:run를 쓸때 클래스패스에 src/main/resources를 직접 추가하지않는다. 만일 사용자가 실시간 즉시 편집을 원하면, Devtools 를 쓰는것을 권장한다. 스프링 부트 1.2에서 했던대로 되돌리려면 addResources 프로퍼티는 pom.xml 에 설정할 수 있다.


    메이븐 리소스 필터링 Maven resources filtering

    spring-boot-starter-parent를 사용한다면, 메이븐 토큰은 오직 @ 을 사용하여 필터링 한다. 이는 사용자 설정에서 빌드시 확장되는 스프링 placeholder를 막아준다.(${foo}와 같은). 

    실제로 만일 사용자가  ${project.version}와 같은 표준화 포멧을 여전히 사용하고 있다면 @project.version@ 로 바꿔주거나 maven-resources-plugin 설정을 오버라이드 해야한다.


    CLI의존성 관리 CLI dependency management

    스프링 부트 1.3은 이제 메타데이터에 기초한 프로퍼티 파일을 대신하여 의존성관리를 설정하기 위해 메이븐 bom을 사용한다. bom의 위치를 지정하기 위한 @GrabMetadata 을 대신하여 @DependencyManagementBomsho을 사용해야한다. 예를 들면,  @DependencyManagementBom("io.spring.platform:platform-bom:1.1.2.RELEASE").


    프로퍼티 이름변경 Property renames

    다음의 application.properties 키들이일관성 차원에서 이름을 변경하였다:

    • spring.view.에서  spring.mvc.view.

    • spring.pidfile 에서 spring.pid.file

    • error.path 에서 server.error.path

    • server.session-timeout 에서 server.session.timeout

    • servet.tomcat.accessLogEnabled 에서 server.tomcat.accesslog.enabled

    • servet.tomcat.accessLogPattern 에서 server.tomcat.accesslog.pattern

    • servet.undertow.accessLogDir 에서 server.undertow.accesslog.dir

    • servet.undertow.accessLogEnabled 에서 server.undertow.accesslog.enabled

    • servet.undertow.accessLogPattern에서 server.undertow.accesslog.pattern

    • spring.oauth2. 에서 security.oauth2.

    • server.tomcat.compression 와 spring.http.gzip 에서server.compression.*

    • prefix.spring.groovy.template.prefix 에서prefix.spring.groovy.resource-loader-location


    의존성 Dependencies


    스프링 4.2 Spring 4.2

    스프링 부트 1.3은 스프링 프레임워크 4.2 또 그 이후 버전이 필요하다. 그 이전버전과는 호환되지않는다.


    스프링 시큐리티 4.0 Spring Security 4.0

    스프링 부트 1.3은 스프링 시큐리티 4.0을 사용한다. 시큐리티 3.2에서 마이그레이션에 대한 정보는 스프링 시큐리티 문서를 확인하자.


    주목할만한 새 기능

    변경된 설정를 둘러보려면 설정 변경기록 을 확인하자.


    버전 업데이트 Version Updates

    스프링 부트 1.3빌드는 스프링 프레임워크 4.2를 필요로 한다. 몇몇 서드파티 의존성이 이 릴리즈에 맞춰 업그레이드 되었다. 이번 릴리즈에는 톰캣과 제티 버전에 주요한 업데이트는 없다.


    개발자 툴 Developer Tools

    스프링부트 1.3 은 개발시간을 향상을 목적으로 하는 새로운 spring-boot-devtools 메소드를 지원한다.이 모듈이 제공하는 것들은:

    • 민감한 프로퍼티의 기본값들 (예를 들면 템플릿 캐시를 disable하는)

    • 어플리케이션 자동 재시작

    • LiveReload 지원

    • 원격 개발 지원 (HTTL터널을 통한 원격 업데이트와 원격 디비깅을 포함).

    • 재시작해도 이어지는 Persistent HTTP 세션

    자세한 정보는 업데이트된 문서를 보자.


    캐싱 자동설정 Caching Auto-configuration

    다음과 같은 캐시 기술에 대한 자동설정이 지원된다:

    • EhCache

    • Hazelcast

    • Infinispan

    • JCache (JSR 107)를 호환하는 구현체들

    • Redis

    • Guava

    더우기, 간단한 Map 기반 메모리 상주 캐싱 또한 지원된다. 캐싱은 사용자의 어플리케이션의  @Configuration이 @EnableCaching와 같이 어노테이션되어있으며 자동적으로 등록된다. 캐시 통계 또한 이제 actuator endpoint로서 노출된다 ( 관련된 근원기술을 허용할때만)

    자세한 정보는 업데이트된 문서를 보자.


    온전히 실행가능한 JAR와 서비스 지원 Fully executable JARs and service support

    스프링 부트 메이븐과 그레들 플러그인은 이제 리눅스/유닉스 시스템을 위한 full executable archives를 만들수 있다. 더우기, 사용자는 이들 JAR들은 다음과 같이 타입함으로서 init.d 또는 systemd 서비스로서 쉽게 인스톨할 수 있다:

    $ ./myapp.jar

    그리고 이렇게 init.d 서비스로 인스톨한다:

    $ sudo link -s /var/myapp/myapp.jar /etc/init.d/myapp

    추가적인 정보는 레퍼런스 문서를 참고하자


    카산드라 지원 Cassandra Support

    카산드라의 자동 설정이 지원된다. 자세한 정보는 레퍼런스 문서를 참고하자.


    OAuth2 지원 OAuth2 Support

    이제 @EnableAuthorizationServer 와 @EnableResourceServer를 사용하여 OAuth2 인증 및 리소스 서버를 재빠르게 만들 수 있다. 뿐만 아니라  @EnableOAuth2Client는 사용자 어플리케이션에  OAuth2 클라이언트로 동작할 수 있게 해준다. 자세한 정보는 재정비된 레퍼런스 문서의 보안섹션을 참고하자.


    스프링 세션 Spring Session

    클래스패스에 스프링 세션과 스프링 데이터 레디스를 넣으면 웹어플리케이션은 이제 레이스에서 사용자 세션을 저장하도록 자동설정될 것이다.  accompanying sample 에서 자세한 정보를 확인하자.


    jOOQ 지원 jOOQ Support

    jOOQ의 자동등록을 지원한다. 형변환에 안전한(type safe) 데이터베이스 쿼리를 만드려면 사용자의 bean에 jOOQ의 DSLContext를 직접  @Autowire 하면된다. 추가적인 커스터마이즈가 spring.jooq.* 어플리케이션 프로퍼티를 통해 지원된다. 

    자세한 정보는 레퍼런스 문서의 "jOOQ 사용하기" 섹션을 참고하자.


    센드그리드 SendGrid

    SendGrid 이메일 배송서비스의 자동등록을 지원한다.


    Artemis 자동설정 Artemis auto-configuration

    2015년 HornetQ가 아파치 재단에 기부하여 아파치 Artemis가 만들어졌다. 스프링 부트 1.3부터 아파치 Artemis를 완벽하게 지원하며 HornetQ와 거의 같은 방식을 사용한다. 사용자가 Artemis 를 사용하려면, spring.hornetq. 프로퍼티를  spring.artemis.로 이름 변경하면 된다.


    "Starter POM" 검증 Validation "Starter POM"

    새로운 spring-boot-starter-validation starter POM 이 추가되어 bean validation (JSR 303) support할 수 있다.


    @WebServlet, @WebFilter와 @WebListener 지원 Support for @WebServlet, @WebFilter and @WebListener

    내장 서블릿 컨테이너를 사용할때 @WebServlet,@WebFilter 그리고 @WebListener 어노테이션된 클래스를 자동등록이 @ServletComponentScan을 사용함으로서 가능해졌다.


    스프링 리소스체인 Spring resource chains

    사용자는 이제 스프링의 application properties를 통해  ResourceChainRegistration 의 기본 aspect을 설정할 수 있다. 이는 사용자가 캐시파열cache busting을 구현하기 위한 고유한 리소스 이름을 만들수 있게 해준다.  spring.resources.chain.strategy.content. 프로퍼티는 만약 사용자가 사용자의 fingerprint에 "고정된 버전"fixed version을 쓰길 원하면 리소스의 내용에 기초해  fingerprinting을 설정하는데 쓰인다. 


    JDBC

    스프링 부트는 다음과 같은 데이터베이스의 JDBC URL로 부터 드라이버 클래스 이름을 자동으로 가져온다:

    • DB2

    • Firebird

    • Teradata


    데이터소스 타입 DataSource type

    자동설정이 사용하는 커넥션 풀connection pool은 spring.datasource.type 설정키를 통해  명시할 수 있다.


    H2 웹콘솔 H2 Web Console

    H2의 web console 의 자동설정이 추가되었다. 스프링부트의 개발자 툴을 쓸때 사용자의 웹 어플리케이션에  com.h2database:h2 의존성만 추가하면 바로 사용할 수 있다. 자세한 정보는 문서를 참고하자.


    내장 몽고DB Embedded MongoDB

    내장 MongoDB 가 자동설정에 추가되었다. de.flapdoodle.embed:de.flapdoodle.embed.mongo 의존성이 시작시 필요하며, 버전과 같은 설정을 사용하려면 application.properties를 통해 설정할 수 있다. 자세한 정보는 문서를 참고하자.


    ANSI 컬러 banner.txt 파일 ANSI color banner.txt files

    이제 사용자의 banner.txt 파일에 출력물에 색깔을 입힐 수 있는 ANSI placeholders를 사용할 수 있다. 예를 들면:

    ${AnsiColor.BRIGHT_GREEN}My Application
    ${AnsiColor.BRIGHT_YELLOW}${application.formatted-version}${AnsiColor.DEFAULT}

     

    기본 프로파일 application.properties Default profile application.properties

    -default 접미사는 이제 특정 프로파일이 활성화되지않았을때 application.properties (또는 application.yml) 파일을 읽는다. 이 것은 사용자가 배포환경을 명시하는 프로파일을 사용할때 유용할 것이다.

    FileDescription

    application.properties

    항상 불러오는 공유 프로퍼티

    application-prod.properties

    prod 프로파일이 활성활됬을때 불러오는 프로퍼티

    application-staging.properties

    staging 프로파일이 활성활됬을때 불러오는 프로퍼티

    application-default.properties

    활성화된 프로파일이 없을때 불러오는 프로퍼티


    어플리케이션 인자들 Application arguments

    사용자는 이제 CommandLineRunner를 대신하는 ApplicationRunner 인터페이스를 구현할 수 있다. 같은 방식으로 동작하지만  String[]이 아닌ApplicationArguments 인터페이스로서 인자를 제공할 수 있다. 만일 사용자가 어플리케이션 인자들에 접근해야한다면, 이미 있는 아무 bean에 직접 ApplicationArguments를 주입할 수 있다.

     ApplicationArguments 인터페이스는  "option" 과 "non-option" 인자들을 위한 편리한 메소드를 제공한다. 예를 들면:

    @Autowired
    public MyBean(ApplicationArguments args) {
        boolean debug = args.containsOption("debug");
        List<String> files = args.getNonOptionArgs();
        // if run with "--debug logfile.txt" debug=true, files=["logfile.txt"]
    }

    어플리케이션 인자 접근하기 에서 자세한 정보를 확인하자.


    로깅 Logging

    로깅 패턴 Log Patterns

    logging.pattern.console 과 logging.pattern.file 프로퍼티는 이제 사용자의 application.properties파일을 통해 직접 로깅패턴을 지정할 수 있다. 사용자의  log*.xml파일을 정의할 필요없이 패턴을 커스터마이즈하길 원하는 경우 손쉽게 이용할 수 있다.


    stacktrace에서 Jar 디테일 Jar details in stacktraces

    사용자가 logback or log4j2를 사용중이라면, stack trace안의 각 클래스의 위치에 대한 정보가 로드될것이다. (이것은 logging.exception-conversion-word를 통해 바꿀 수 있다.) 

    If you are using logback or log4j2, we now include information about the location from which each class in a stack trace was loaded (this can be customized vialogging.exception-conversion-word).


    Log4J 2 출력 Log4J 2 Output

    Log4J 2’의 기본 출력이 향상되어 Logback의 출력물과 비슷해졌다.


    톰캣 접근 로그 Tomcat access logs

    톰캣 접근로그(access logs)는 더 커스커마이징할 수 있게 되었다: 디렉토리, 파일의 접두사/접미사를 이제 설정을 통해 커스터마이즈 할 수 있다.


    로그백 확장 Logback extensions

    스프링 부트 1.3은 사용자가 logback 설정파일안에서 사용할 수 있는 몇 개의 새로은 태그를 지원한다. 태그를 쓰려면 사용자는 먼저 logback.xml 설정파일을 logback-spring.xml로 이름을 바꿔줘야 한다. 일단 이름을 바꿨다면 다음의 태그를 사용할 수 있다:

    태 그

    설 명

    <springProfile>

    사용자 마음대로 활성화된 스프링 프로퍼티에 기초한 설정을 포함하던지 배제할지 허용한다.

    <springProperty>

    Logback에서 사용하는 스프링 환경변수(Spring Environment)의 프로퍼티를 불러오는 것을 허용한다.

    레퍼런스 문서의 Logback extensions 섹션에서 자세한 정보를 확인하자.


    HTTP 세션 HTTP Sessions


    Persistent 세션 Persistent sessions

    톰캣, 제티, Undertow는 어플리케이션이 멈췃을때와 재시작되어 다시 로드될때 세션데이터를 serialize하도록 업데이트되었다. Persistent  세션은 opt-in이라  ConfigurableEmbeddedServletContainer의 persistentSession 이나  server.session.persistent=true 프로퍼티를 사용하여 설정할 수 있다. (Persistent 세션은 Devtools에서 기본적으로 enabled 되어있다)

    persistent 세션 데이터를 저장하는 위치는 server.session.store-dir 프로퍼티를 사용하여 지정할 수 있다.


    향상된 HTTP 세션 설정 Advanced HTTP Session configuration

    부가적인 프로퍼티들이 세션 설정을 위해 제공되어 이제 server.session.* 프로터리를 사용하여 "tracking modes" 와 "cookie" details을 설정할 수 있다.


    X-Forwarded-For 헤더지원 X-Forwarded-For header support

    X-Forwarded-For header 지원이 제티와 Undertow에 추가되었다. 톰캣 또한 X-Forwarded-For headers를 반영되어야 한다면 단일 server.use-forward-headers 프로퍼티를 true로 설정 할 수 있도록 새로 고쳐졌다. 스프링부트는 Cloud Foundry 나 Heroku의 배포를 감지하여 자동으로 enable되도록 지원한다.


    설정 프로퍼티 Configuration properties

    Bean에서 @ConfigurationProperties 를 사용하고 있다면, 사용자는 더이상 스프링 부트의 자동설정으로의 당신의 설정파일에 @EnableConfigurationProperties 를 추가해주지 않아도 된다. 기존엔 @EnableConfigurationProperties 의 값속성을 사용하거나 정식으로 하는 @Bean 정의를 함으로서 사용자의  @ConfigurationProperties클래스를 위해 스프링에 bean을 만들라고 했었다.

     

    메세징 Messaging

    JMS와 Rabbit endpoints 둘다 이제 설정을 통해 쉽게 disabled할 수 있게 되었다. 아무 설정없이 생성된 기본 컨테이너 팩토리가 있다면 또한 설정을 통해 커스터마이즈 할 수 있다.


    국제화 Internationalization

    자동설정된 MessageSource 인스턴스의 fallbackToSystemLocale 플래그를 spring.messages.fallback-to-system-locale 설정키를 통해 제어할 수 있다.


    자동설정 Auto-configuration

    자동설정 리포트는 "Unconditional classes"라 불리는 추가적인 섹션을 가진다. 이것은 어떤 클래스레벨 조건을 가지지 않은 자동설정 클래스를 리스트해준다. 예를 들면 언제나 어플리케이션 설정의 한 부분인 클래스 @SpringBootApplication(exclude=…​)또는 @EnableAutoConfiguration(exclude=…​)를 통해 수동으로 배재excluded된 설정에 리스트되어질 것이다.

    spring.autoconfigure.excludes 프로퍼티를 통해 자동설정 클래스에서 제외하는것 또한 가능해졌다. 유사하게 새 @ImportAutoConfiguration 어노테이션을 써서 특정 자동설정 클래스를 선별적으로 import해야하는 테스트를 할 수 있다.


    MVC 에러 핸들링 MVC Error handling

    error.include-stacktrace 프로퍼티는 스택 트레이스 속성을 MVC 에러 응답에 넣을지 결정하는데 사용한다. 옵션은 neveralways 또는 on-trace-param 이 있다. (기본값은 never).


    엑츄에이터 메트릭스 Actuator Metrics

    spring-boot-actuator 메트릭스가 export 와 aggregation을 지원하도록 확장되었다. 또한 자바8 특화 GaugeService 와 CounterService 구현이 제공되어 개선된 성능을 제공해준다.

    자세한 정보는 확장된 metrics documentation for details.


    부가적인 Health Indicators

    다음의 부가적인  HealthIndicators  제공되어 자동설정된다.:

    • Elasticsearch

    • Email

    • JMS


    새로운 actuator endpoints

    다음의 부가적인 actuator endpoints 가 스프링부트 1.3에 추가되었다:

    이름설 명

    /logfile

    로그파일로 접근할 수 있다.(설정해두었을경우).

    /flyway

    적용해둔 Flyway 데이터베이스 마이그레이션의 자세한 정보를 제공한다.

    /liquibase

    적용해둔 Liquibase 데이터베이스 마이그레이션의 자세한 정보를 제공한다.


    액츄에이터 종단을 위한 CORS지원 CORS support for actuator endpoints

    Actuator’s endpoint는 이제 CORS를 지원한다. 기본값은 disabled되어 있지만 endpoints.cors.allowed-origins.설정을 enabled함으로서 사용할 수 있다.


    /env와 /metrics를 위한 정규식 지원 Regex support for /env and /metrics

    사용자는 정규식을 사용하여 /env and /metrics actuator endpoints를 필터할 수 있다. 예를들면,  http://localhost:8080/metrics/.root..


    MVC 액츄에이터 종단을 위한 하이퍼미디어 Hypermedia for MVC actuator endpoints

    Actuator HTTP endpoints는 이제 사용자가 클래스패스에 Spring HATEOAS가 있으면 (예를 들면,  spring-boot-starter-hateoas를 통해), 하이퍼링크를 보여줄 수 있게 개선되었다. 새로운 "discovery page" 또한 모든 actuator endpoints의 링크들을 제공해준다. 클래스패스에 HAL browser의 webjar가 있으면 HAL browser를 위한 지원 또한 제공된다. 자세한 정보는 "Hypermedia for MVC Endpoints"  레퍼런스 섹션을 보자.


    Actuator docs endpoint

    새로운 spring-boot-actuator-docs 모듈이 스프링 부트 1.3에 추가되어 actuator 문서를 사용자 어플리케이션에 내장하는것이 가능해졌다. 일단 해당 모듈이 클래스패스에 있다면, 사용자는 /docs를 타입하여 각각 endpoint에서 리턴받은 데이터의 샘플을 포함하는 actuator endpoints의 정보를 얻을 수 있다.


    Disabling health indicators

    management.health.defaults.enabled 프로퍼티를 통해 기본 health indicators를 전부 손쉽게 disable시킬수 있다.


    TraceWebFilter options

    (HTTP 요청/응답의 디테일을 추적하는데 쓰이는Actuator TraceWebFilter 가 이제 더 많은 정보를 로그한다.이것을 사용하려면  management.trace.include 프로퍼티를 쓰면된다. (TraceProperties.Include enum을 참고하자)


    메이븐 지원 Maven Support


    Maven start/stop support and admin features

    메이븐 플러그인에  start 과 stop goals이 추가되었다. 이들은 메이븐의 방해없이 어플리케이션을 시작할 수 있게 해준다.( 다른 goals이 어플리케이션을 가동할수 있게 해줌으로서). 이 기술은 메이븐으로부터 통합테스트를 실행할때 자주 쓰인다.

    이 작업의 부산물로서 새로운 SpringApplicationAdminMXBean 인터페이스가 추가되어 스프링 부트 어플리케이션이 JMX를 통해 제어될수있게 허용되었다 (enabled 설정했을경우)


    Profile activation

    spring-boot-maven-plugin은 spring-boot:run.과 함께 사용할 수 있는 profiles 프로퍼티를 제공한다. 사용자의 pom.xml 에서 또는 커맨드라인에서 -Drun.profiles 을 사용함으로서 프로파일을 설정할 수 있다. 자세한 정보는 updated plugin documentation 를 참고하자.


    Ant Support

    스프링 부트는 이제 Ant를 통해 실행가능한 jars를 만들 수 있는 AntLib 모듈을 제공한다. 레퍼런스 문서의 "Spring Boot AntLib module" 섹션을 보라.


    Configuration property meta-data updates

    META-INF/spring-configuration-metadata.json 파일포멧이 업데이트되어 새로운 deprecation 과 hints 속성을 지원한다. Hints는 IDE개발자가 사용하여 더 나은 컨텐트 도움말을 보여줄 수 있으며, Deprecation은 deprecation과 replacement key를 설정할 수 있다. 만일 필요하다면 그러한 정보들은 프로퍼티의 getter에 @DeprecatedConfigurationProperty 를 추가함으로서 제공할 수 있다. updated appendix 에서 자세한 정보를 확인하자.

    기본값의 인식 또한 향상되었다: 만일 프로퍼티가 단일 인자를 가지는 하나의 메소드호출을 통해 초기화되면, 해당 인자가 초기값으로 간주될 것이다. (예를들면, Charset.forName("UTF-8") 은 기본값으로 UTF-8 으로 인식된다)

    자신의 툴과 앱에서 configuration meta-data을 사용하고 싶어하는 툴개발자를 위해 새로운 spring-boot-configuration-metadata 모듈이 추가되었다. 이것은 메타데이터를 읽고 그것을 리파지토리에서 빌드할 수 있는 API가 제공된다.


    Spring Boot CLI

    CLI 는 이제 의존성 해결dependency resolution동안 메이븐 settings.xml 의 리파지토리 설정을 사용할 수 있다. 리파지토리를 쓰려면 프로파일에 활성화해줘야 한다.

    CLI 는 또한 이제 실행가능한 WAR파일을 만들수 있다. $ spring war <filename.war> <script.groovy>를 사용하자.


    Miscellaneous

    다음과 같은 잡다한 업데이트 또한 스프링 1.3에 포함되었다:

    • 자바8을 쓰면 잭슨의 자바8 모듈이 자동적으로 등록된다.

    • TransactionTemplate bean 은 이제 TransactionAutoConfiguration의 일부로 포함되었다.

    •  MailServer bean 은 이제 spring.mail.jndi-name 프로퍼티를 사용하는 JNDI를 통해 얻어진다.JNDI 

    • 사용자는 이제  server.display-name 프로퍼티를 통해 서블릿 이름을 등록할 수 있다. (내장 서블릿 컨테이너를 쓸때) 

    • Flyway migration strategies 은 이제 FlywayMigrationStrategy bean를 통해 설정할 수 있다.

    • 새로운 SpringBootVersion  클래스가 추가되었다. (코어프레임워크의 SpringVersion 과 유사하다).

    • 사용자는 이제 amcrest matchers를 OutputCapturet과 같이 사용하여 특정한 결과의 테스트 산출물을 검증할 수 있다.

    •  사용자는 이제 Elasticsearch non local nodes를 사용해서 스프링 부트를 설정할 수 있다.

    • ApplicationPidFileWriter는 이제 fail-on-write-error프로퍼티를 통해 exception 설정을 할 수 있다. (업데이트된 javadoc를 참조하자)

    • 메이븐 플러그인은  spring-boot:run과 함께 사용할 수 있는 useTestClasspath 옵션이 추가되었다.

    • DB2와 Informix를 위한 추가적인 데이터베이스 heath 쿼리가 추가되었다.

    • 프로퍼티 바인딩 실패는 이제 더 나은 Exception 메시지를 보여준다.

    • @SpringBootApplication 어노테이션에  scanBasePackages 와 scanBasePackageClasses 속성이 추가되었다.

    • 새로운 AllNestedConditions 과 NoneNestedConditions 가 추가되었다. (현존하는 AnyNestedCondition과 비슷)

    • 활성화된 프로퍼티Active profiles는 이제 어플리케이션이 시작할때 출력로그output log를 프린트한다.

    • spring.main.banner-mode 프로퍼티는 CONSOLELOG 또는 OFF output 간에 스위치하는데 사용할 수 있다.

    • 원격 DevTools 은 이제 프록시 서버뒤에서 작동한다. (spring.devtools.remote.proxy.* 프로퍼티를 보자)

    • (Java 8 에서 지원하는) 잭슨의 parameter names module가 이제 사용자의클래스패스에 있으면 자동설정된다.

    • 스프링의 웹소켓 메세지 변환기message converters는 이제 자동설정된다.

    • 새로운 DelegatingFilterProxyRegistrationBean 클래스가 추가되어 DelegatingFilterProxy.를 거친 내장 서블릿 컨테이너와 함께 등록할 수 있게 되었다.


    Deprecations in Spring Boot 1.3.0

    •  setBannerMode사용을 유도하기 위해 Application.showBanner와 ApplicationBuilder.showBanner메소드는 디프리케이트되었다.

    • @ConditionalOnMissingClass는 이제  name.보다 value 속성을 사용하여 제공되기때문에 클래스 이름이 필요하다.

    • 아파치의 log4j 1.x의 서비스 종료(EOL)선언에 따라 Log4JLoggingSystem 는 디프리케이스되었다.

    • ConfigurableEmbeddedServletContainer setJspServletClassName 과 setRegisterJspServlet 메소드는 setJspServlet로 대체되었다.

    • EndpointMBean 클래스(와 서브클래스들)은 이제 생성자에 제공되려면 ObjectMapper 이 필요하다.

    • DropwizardMetricWriter 는 DropwizardMetricService로 대체되었다.

    • String[] 을 가지는 protected SpringApplication.afterRefresh 메소드는 ApplicationArguments.을 가지는 버젼에 의해 디프리케이트되었다.

    • CloudFoundryVcapEnvironmentPostProcessor에 의해 VcapEnvironmentPostProcessor 는 디프리케이트되었다.

    • LoggingSystem initialize 메소드는 LoggingInitializationContext받는 버젼에 의해 디프리케이트 되었다.

    • org.springframework.boot.autoconfigure.orm.jpa.EntityManagerFactoryBuilder 는 디프리케이트되어 새 패키지  org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder를 사용해야한다.


    반응형

    + Recent posts