[error/log] vue axios url controller 접근

아무튼 간에·2020년 8월 25일
0

* 개발환경
- Vue CLI 4.4.6
- SpringBoot / SpringSecurity
- Tomcat 9.0
- JDK 1.8
- Gradle

- 문제 1

  1. vue프로젝트의 js파일에서 axios로 요청할 주소를 입력했지만 해당 주소를 가진 Controller를 타지 않음.
  2. axios 전송 결과를 console로 출력 시 status는 200이라고 나오지만
  3. network 탭에서 확인 시 status가 302로 반환

- 목표 로직 플로우

  1. FindPasswordModal.vue에서 찾기 클릭 시 doFind 메서드 실행.
  2. doFind에 정의된 목적 url을 가지고 loginAjaxUtil.js로 분리해놓은 axios 로직을 탐.
  3. loginAjaxUtil.js의 post 메서드에서 axiosCheck 메서드를 사용해 파라미터로 받은 url로 비동기 통신.
  4. Controller는 파라미터를 @RequestBody Map으로 받고 Map으로 반환.

- FindPasswordModal.vue 일부

<template>
...

<button @click="doFind">찾기</button>

...
</template>
<script>
...

 methods:{
    doFind: async function() {
     var result = await this.$ajax.post({
        url: "/findPasswordPage.json",	// controller 탈 mapper
          data: this.$data		// 넘길 데이터
        });
    }
}
...
</script>

- loginAjaxUtil.js 일부

import axios from 'axios'		// axios 임포트

export default {
  axiosCheck: function(param) {		// 비동기 로직
    if (typeof param == "string" ) {
      return axios.post(param);
    } else {
      param.method = 'post';
      if (param.data != null ) {
        param.data = JSON.stringify(param.data);
      }
      param.headers = {'Content-Type' : "application/json"};
      return axios(param);
    }
  },
  post: async function(param) {		// 비동기 처리 후 작업
    var returnVal;
     try {
       var response = await this.axiosCheck(param); // axios 결과
       console.log(response)
       returnVal = response.data;
    } catch(e) {
      window.console.log(e);
    }
    return returnVal;
  } 
}

- FindPasswordController.java

...

@Controller
public class FindPasswordController {

	...
	@PostMapping("/findPasswordPage")
    public Map<String,Object> findPassword(@RequestBody Map<String, Object> param) {
    	Map<String,Object> result = new HashMap<String,Object>();
    	System.out.println("param:::::::" + param);
        return result;
    }
}

원인 파악 및 해결

(순서는 중요하지x)

- 원인 1. SpringSecurity

스프링 시큐리티의 페이지별 접근 퍼미션 문제.
: SecurityConfiguration.java 중 HttpSecurity를 파라미터로 받는 configure 메서드에서 해당 uri 패턴에 대한 접근 설정이 없음.
ex) .antMatchers("주소or패턴").permitAll() 혹은 .hasAurhority("권한")

- 해결 >>> 해당 uri에 접근 권한 설정 추가

authorizeRequests().antMatchers("/findPasswordPage.json").permitAll()을 추가함.

- SecurityConfiguration.java 중 configure(HttpSecurity)

...

@Configuration
@EnableWebSecurity
@ConditionalOnProperty(prefix = "spring.security", name = "enabled", matchIfMissing = false)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
	
    ...
	
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
        .headers().frameOptions().disable()
        .and()
        .authorizeRequests()
           	.antMatchers("/test*").permitAll()
        	.antMatchers("/loginPage.action").permitAll()
            .antMatchers("/findPasswordPage.json").permitAll()	// 접근 권한 설정 추가
            .antMatchers("/login").permitAll()
            .antMatchers("/registration").permitAll()
            .antMatchers("/main").hasAuthority("ADMIN")
            .antMatchers("/home").hasAuthority("ADMIN") 
        .anyRequest()
            .authenticated()
        
        ...
        
    }
}

- 원인 2. SpringBoot WebMvcConfigure의 Interceptors

권한 체크와 로그를 위해 각각 interceptor를 사용하고 있음.

현재 프로젝트는 어떤 uri에 접근할 땐 무조건 권한 체크 인터셉터를 먼저 타게 됨. 권한을 체크해야 하는 uri 목록은 모두 사용자의 권한(이미 로그인을 해서 사용자 인증이 완료됐다는 가정이 필요하게 됨)에 따라 접근 가능한 uri들이며, 모두 DB에 저장되어 있음. Interceptor는 사용자 인증 완료 시 이 uri 목록을 들고와서 Account 객체에 담아놓음.

현재 접근하고자 하는 uri는 현재 권한체크를 해야하는 uri패턴에 걸림. 그러나 이 uri는 로그인 이전에 필요한 화면(비밀번호 찾기 화면)이기 때문에 권한 체크가 필요하지 않고, DB에도 없기 때문에 uri목록에 없음. 그래서 AuthInterceptor는 false를 반환하고 이로 인해 해당 uri에 접근하지 못함.

- 해결 >>> Interceptor 패턴에서 제외시키기

excludePathPatterns()"/findPasswordPage.json" 추가

- WebConfig.java(implements WebMvcConfigurer) 중 addInterceptors(InterceptorRegistry)

...

@Configuration
@EnableWebMvc
@ConfigurationProperties(prefix = "ui")
public class WebConfig implements WebMvcConfigurer {

	...

    @Override
	public void addInterceptors(InterceptorRegistry registry) {
    	logger.info("addInterceptors start");
    	if(securityEnabled ) {
        	
            	// AuthInterceptor() : 권한 체크 Interceptor
    		registry.addInterceptor(new AuthInterceptor())
    		.addPathPatterns("/*.action")
    		.addPathPatterns("/*.json")	// interceptor 패턴에 걸림
    		.excludePathPatterns("/test*.json", "/manifest.json","/findPasswordPage.json")	// interceptor 제외 패턴에 추가
			.excludePathPatterns(loginPageUrl);
           ...
    		
    		}
	}
...

}

- 문제 2

여기까지 하면 해당 uri로 Controller가 타고 들어오기는 하지만 org.thymeleaf.exceptions.TemplateInputException: Error resolving template 에러가 발생.

2020-08-25 15:39:02.889 ERROR 22852 --- [nio-8080-exec-1] org.thymeleaf.TemplateEngine             : [THYMELEAF][http-nio-8080-exec-1] Exception processing template "findPasswordPage": Error resolving template [findPasswordPage], template might not exist or might not be accessible by any of the configured Template Resolvers

org.thymeleaf.exceptions.TemplateInputException: Error resolving template [findPasswordPage], template might not exist or might not be accessible by any of the configured Template Resolvers
	at org.thymeleaf.engine.TemplateManager.resolveTemplate(TemplateManager.java:869)
	at org.thymeleaf.engine.TemplateManager.parseAndProcess(TemplateManager.java:607)
	at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1098)
	at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1072)
	at 
...

- 원인 파악 및 해결

- 원인: 비동기 통신의 리턴 타입

Controller가 결과를 return해줄 화면을 지정하는 과정에서 해당 주소를 가진 화면을 찾지 못해서 발생하는 문제. 비동기 통신은 화면을 찾아서 리다이렉트 하지 않는 대신 결과 객체만 리턴하기 때문에 리턴할 화면이 지정되지 않음.

- 해결1 >>> Controller의 return type에 @ResponseBody 어노테이션 붙이기

- FindPasswordController.java

...

@Controller
public class FindPasswordController {
@PostMapping("/findPasswordPage")
  public @ResponseBody Map<String,Object> findPassword(@RequestBody Map<String, Object> param) {
      Map<String,Object> result = new HashMap<String,Object>();
      System.out.println("param:::::::" + param);
      return result;
  }
}
       

- 해결2 >>> Controller를 @RestContoller로 선언하기

- FindPasswordController.java

@RestController
public class FindPasswordController {
	...
}
profile
armton garnet

0개의 댓글