HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
🤩
개발
/
🔐
Spring Security
/
🥼
Multi Filter Chain 이용 (웹, 모바일 동시 개발)
🥼

Multi Filter Chain 이용 (웹, 모바일 동시 개발)

웹사이트, 모바일 서비스 개발(두개의 정책을 사용해야 할 시)웹 쪽 개발 예시API 측테스트 코드

웹사이트, 모바일 서비스 개발(두개의 정책을 사용해야 할 시)

// 모바일쪽 - CSRF disable & BasicAuthenticationFilter 이용 @Order(1) @Configuration // EnableWebSecurity 와 EnableGlobalMethodSecurity는 중복 해서쓰면안됨 public class MobileSecurityConfig extends WebSecurityConfigurerAdapter { private final StudentManager studentManager; private final TeacherManager teacherManager; @Override protected void configure(HttpSecurity http) throws Exception { CustomLoginFilter filter = new CustomLoginFilter(authenticationManager()); http .antMatcher("/api/**") .csrf().disable() .authorizeRequests(request-> request.anyRequest().authenticated() ) .httpBasic() ; } } // 웹사이트 쪽 - csrf 이용 @Order(2) @EnableWebSecurity(debug = true) @EnableGlobalMethodSecurity(prePostEnabled = true) public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { CustomLoginFilter filter = new CustomLoginFilter(authenticationManager()); http .authorizeRequests(request-> request.antMatchers("/", "/login").permitAll() .anyRequest().authenticated() ) // .formLogin(login -> login.loginPage("/login").permitAll() // .defaultSuccessUrl("/", false) // .failureUrl("/login-error")) .addFilterAt(filter, UsernamePasswordAuthenticationFilter.class) .logout(logout -> logout.logoutSuccessUrl("/")) .exceptionHandling(e -> e.accessDeniedPage("/access-denied")) ; } @Override public void configure(WebSecurity web) throws Exception { web.ignoring() .requestMatchers(PathRequest.toStaticResources().atCommonLocations()) ; } }

웹 쪽 개발 예시

public String main(@AuthenticationPrincipal Teacher teacher, Model model){ model.addAttribute("studentList", studentManager.myStudentList(teacher.getId())); return "TeacherMain"; }
  • model.addAttribute는 template에서 해당 attribute를 사용할 수 있도록 해줌

API 측

@PreAuthorize("hasAnyAuthority('ROLE_TEACHER')") @GetMapping("/students") public List<Student> main(@AuthenticationPrincipal Teacher teacher){ return studentManager.myStudentList(teacher.getId()); }
  • @AuthenticationPrincipal을 이용하여 authenticate 된 Authentication의 Principal을 얻어와서 인자로 사용함

테스트 코드

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class MultiChainProxyTest { @LocalServerPort int port; RestTemplate restTemplate = new RestTemplate(); @DisplayName("1. 학생 조사") @Test void test_1() throws JsonProcessingException { String url = String.format("http://localhost:%d/api/teacher/students", port); HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.add(HttpHeaders.AUTHORIZATION, "BASIC " + Base64.getEncoder().encodeToString( "choi:1".getBytes() )); HttpEntity<String> entity = new HttpEntity<>("", httpHeaders); ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, entity, String.class); List<Student> list = new ObjectMapper().readValue( response.getBody(), new TypeReference<List<Student>>() { }); System.out.println(list); Assertions.assertEquals(3, list.size()); } }
  • TypeReference 는 Jackson(Json타입), ParameterizedTypeReference는 RestTemplate에서 쓰임