인프런 영문 브랜드 로고
인프런 영문 브랜드 로고

인프런 커뮤니티 질문&답변

강프로그래머님의 프로필 이미지

작성한 질문수

스프링 시큐리티

3) 어노테이션 권한 설정 - @PreAuthorize, @PostAuthorize, @Secured, @RolesAllowed

AbstractSecurityInterceptor.class.beforeInvocation()를 2번 실행하는 경우

해결된 질문

작성

·

71

·

수정됨

0

image.pngimage.png
@Order(0)
@Configuration
@EnableWebSecurity
public class SecurityConfig2 extends WebSecurityConfigurerAdapter {
    @Autowired private SecurityResourceService securityResourceService;
    @Autowired private FormAuthenticationDetailsSource authenticationDetailsSource;
    @Autowired private AuthenticationSuccessHandler customAuthenticationSuccessHandler;
    @Autowired private AuthenticationFailureHandler customAuthenticationFailureHandler;
    private String[] permitAllPattern = {"/", "/login", "/user/login/**"};

    @Bean
    public PermitAllFilter customFilterSecurityInterceptor() throws Exception {
        PermitAllFilter permitAllFilter = new PermitAllFilter(permitAllPattern);
        permitAllFilter.setSecurityMetadataSource(urlFilterInvocationSecurityMetadataSource());
        permitAllFilter.setAccessDecisionManager(affirmativeBased());
        permitAllFilter.setAuthenticationManager(authenticationManagerBean());
        return permitAllFilter;
    }

    private AccessDecisionManager affirmativeBased() {
        AffirmativeBased affirmativeBased = new AffirmativeBased(getAccessDecisionVoters());
        return affirmativeBased;
    }

    private List<AccessDecisionVoter<?>> getAccessDecisionVoters() {
        List<AccessDecisionVoter<? extends Object>> accessDecisionVoters = new ArrayList<>();
        accessDecisionVoters.add(new IpAddressVoter(securityResourceService));
        accessDecisionVoters.add(roleVoter());
        return accessDecisionVoters;
    }

    @Bean
    public RoleHierarchyVoter roleVoter() {
        RoleHierarchyVoter roleHierarchyVoter = new RoleHierarchyVoter(roleHierarchy());
        return roleHierarchyVoter;
    }

    @Bean
    public RoleHierarchyImpl roleHierarchy() {
        RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
        return roleHierarchy;
    }

    @Bean
    public FilterInvocationSecurityMetadataSource urlFilterInvocationSecurityMetadataSource() throws Exception {
        return new UrlFilterInvocationSecurityMetadataSource(urlResourcesMapFactoryBean().getObject(), securityResourceService);
    }

    private UrlResourcesMapFactoryBean urlResourcesMapFactoryBean() {
        UrlResourcesMapFactoryBean urlResourcesMapFactoryBean = new UrlResourcesMapFactoryBean();
        urlResourcesMapFactoryBean.setSecurityResourceService(securityResourceService);
        return urlResourcesMapFactoryBean;
    }

    @Bean
    public AuthenticationProvider authenticationProvider() {
        return new FormAuthenticationProvider(passwordEncoder());
    }

    @Bean
    public AccessDeniedHandler accessDeniedHandler() {
        CustomAccessDeniedHandler accessDeniedHandler = new CustomAccessDeniedHandler();
        accessDeniedHandler.setErrorPage("/denied");
        return accessDeniedHandler;
    }

    @Bean
    public AuthenticationSuccessHandler ajaxAuthenticationSuccessHandler() {
        return new AjaxAuthenticationSuccessHandler();
    }

    @Bean
    public AuthenticationFailureHandler ajaxAuthenticationFailureHandler() {
        return new AjaxAuthenticationFailureHandler();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return PasswordEncoderFactories.createDelegatingPasswordEncoder();
    }

    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) {
        auth.authenticationProvider(authenticationProvider());
    }

    @Override
    public void configure(WebSecurity web) {
        web.ignoring()
           .requestMatchers(PathRequest.toStaticResources()
                                       .atCommonLocations());
    }

    @Override
    protected void configure(final HttpSecurity http) throws Exception {
        http.authorizeRequests()
            .antMatchers("/").permitAll()
            .antMatchers("/mypage").hasRole("USER")
            .antMatchers("/messages").hasRole("MANAGER")
            .antMatchers("/config").hasRole("ADMIN")
            .anyRequest().authenticated()
            .and()
            .formLogin()
            .loginPage("/login")
            .loginProcessingUrl("/login_proc")
            .authenticationDetailsSource(authenticationDetailsSource)
            .successHandler(customAuthenticationSuccessHandler)
            .failureHandler(customAuthenticationFailureHandler)
            .permitAll()
        ;
        http.exceptionHandling()
            .authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login"))
            .accessDeniedPage("/denied")
            .accessDeniedHandler(accessDeniedHandler())
            .and()
            .addFilterBefore(customFilterSecurityInterceptor(), FilterSecurityInterceptor.class)
        ;
        http.csrf()
            .disable();

        customConfigurer(http);
    }

    private void customConfigurer(HttpSecurity http) throws Exception {
        http.apply(new AjaxLoginConfigurer<>())
            .successHandlerAjax(ajaxAuthenticationSuccessHandler())
            .failureHandlerAjax(ajaxAuthenticationFailureHandler())
            .setAuthenticationManager(authenticationManagerBean())
            .loginProcessingUrl("/api/login");
    }
}

답변 1

0

인프런 AI 인턴님의 프로필 이미지

안녕하세요, 인프런 AI 인턴입니다.

AOP 관련 설정에서 AopSecurityController.preAuthorize()가 두 번 실행되는 문제에 대해 질문해 주셨습니다. 우선, 이와 관련한 질문은 아래의 유사한 형태로 언급된 적이 있습니다. 스프링 시큐리티 설정에서 불필요하게 두 번 호출되는 것을 방지하기 위한 구체적인 해결 방법에 대해 설명드리겠습니다.

관련 질문

설명 및 조치 스프링 시큐리티의 `WebSecurity` 설정에서 정적 리소스(`/static`, `/css`, `/js`, `/images`, `/webjars`)를 무시하도록 설정하셨습니다. 하지만 `AopSecurityController.preAuthorize()`가 두 번 실행되는 문제는 시큐리티 설정 상에서 불필요한 내부 호출이 있을 수 있습니다. 이를 방지하기 위해 설정의 중복 부분이나 불필요한 컴포넌트 주입이 없는지 검토해 보셔야 합니다. 1. **Web Security 설정 확인**: - 예를 들어, 동일한 패턴이나 URL에 대해 여러 번 매칭이 발생하지 않도록 설정합니다. 2. **AOP 설정 검토**: - AOP 설정이 중복 실행되거나 불필요한 지점에서 실행되지 않도록 어드바이스 호출 조건이나 포인트컷을 검토하십시오. 3. **역할 기반 접근 제어**: - 특정 메소드에서 동일한 접근 권한이 두 번 체크되고 있는지 확인해 보세요. 이와 관련하여 추가적인 정보가 필요하시다면, 관련 코드를 분석하여 말씀드릴 수 있습니다.

위 방법으로 해결되지 않거나 명확한 오류 원인을 찾기 어려우시면, 궁금한 점을 더 구체적으로 알려주시면 도움이 될 것입니다.

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다. 현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏 추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.