최근 AngularJS에 대한 공부와, Yeoman에 대한 공부를 마치고, Yeoman을 사용한 프론트 세팅과 실행, 그리고 갑작스럽지만 내게는 딱 맞다 생각하는 Spring-Boot의 약간의 공부를 진행했다. 뭐 스프링 부트는 공부할 것도 없었지만..
Gradle이란 놈이 참으로 훌륭하더라. 여기에 Front/Backend의 프로젝트와 의존성을 물려놓고, 서로 커멘드 등의 명령어를 통해 실행하니 정말 잘 모듈별로 독립적이면서도 잘 맞물린다.
이제는 기존 Spring MVC와 Velocity, MyBatis로 구성된 소스를 SpringBoot – Hibernate(JPA)그리고 AngularJS를 통해 구성하기. 가장 기본적인 것은 로그인인데, 이 참에 Spring-Security를 적용해 보기로 하고, 가장 적절한 강좌를 찾았다.(아래 링크)
https://spring.io/guides/tutorials/spring-security-and-angular-js/
그런데 문제는, 이 강좌의 경우는 리소스를 WEB-INF에 넣고 AngularJS를 Spring Boot와 함께 돌리는데, 내 경우는 Spring-Boot는 Embedded Tomcat으로 8080포트를, AngularJS는 Yeoman으로 생성했기 때문에 node.js를 통해 9000포트가 되버렸다. 물론 나도 함께 구동하고 싶은 욕심은 있지만, 이걸 함께 구동하면 모듈화의 의미가 없어지기 때문에..
결국, 그렇게 해서 저 튜토리얼을 따라가다 보니 Cross-Domain문제에 직면했다. 인터넷을 찾아보니 아래 처럼 Filter를 implement해서 access-control을 정의하란다.
@Component
public class FiammCORSFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
chain.doFilter(req, res);
}
public void init(FilterConfig filterConfig) {}
public void destroy() {}
}
그런데 이 필터가 전혀! 먹히지 않는다. 크롬 디버거로 HTTP헤더를 봐도, 적용이 안되었다..
그래서 혹시나 해서, 위 강좌에 나온 CsrfHeaderFilter 안에다가 저 내용을 넣어봤더니, 그제서야 먹는다..
public class CsrfHeaderFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class
.getName());
if (csrf != null) {
Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
String token = csrf.getToken();
if (cookie==null || token!=null && !token.equals(cookie.getValue())) {
cookie = new Cookie("XSRF-TOKEN", token);
cookie.setPath("/");
response.addCookie(cookie);
}
}
response.setHeader("Access-Control-Allow-Origin", "http://localhost:9000");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
filterChain.doFilter(request, response);
}
}
저렇게, Access-Control-Allow-Origin에 나의 경우는 http://localhost:9000을 넣어주고,
angular.module('frontendApp')
.controller('LoginCtrl', function($rootScope, $scope, $http, $location) {
// Authentication
var authenticate = function(credentials, callback) {
var headers = credentials ? {
authorization:"Basic " + btoa(credentials.userId + ":" + credentials.passwd)
} : {};
$http.get($rootScope.serverUrl+'/doLogin', {headers:headers}).success(function(data) {
if(data.userName) {
$rootScope.authenticated = true;
}else{
$rootScope.authenticated = false;
}
}).error(function(data) {
$rootScope.authenticated = false;
callback && callback();
});
}
authenticate();
$scope.credentials = {};
$scope.login = function() {
authenticate($scope.credentials, function() {
if($rootScope.authenticated){
$location.path("/");
$scope.error = false;
}else{
$location.path("/login");
$scope.error = true;
}
});
}
});
위에서처럼 $rootScope.serverUrl+'/doLogin' 를 통해 통신하게 했다. $rootScope.serverUrl은 App.js에
angular
.module('frontendApp', [
'ngAnimate',
'ngCookies',
'ngResource',
'ngRoute',
'ngSanitize',
'ngTouch',
'ui.sortable'
])
.run(['$rootScope','$http', function($rootScope, $http){
// Definition to Global Variables and Functions
$rootScope.serverUrl = "http://localhost:8080"
});
}]);
이런식으로 마치 전역변수처럼 서버 URL을 생성해 두었다. 물론, 나중에 배포 문제 때문에 직접 URL을 쓰지 않고 $location 을 사용하여 바꿀 예정이다.



