Spring 3 Security: AccessDeniedHandler не вызывается - PullRequest
16 голосов
/ 10 августа 2011

У меня есть приложение Spring 3 с конфигурациями, приведенными ниже. Когда какой-либо пользователь пытается получить доступ к странице и он / она не вошел в систему, я получаю исключение Отказано в доступе с ужасной трассировкой стека. Как мне обработать это исключение и не дать ему сбросить трассировку стека. Я реализовал свой собственный обработчик отказа в доступе, но он не вызывается.

В зависимости от типа запрашиваемого ресурса, я хотел бы показать пользовательские сообщения об ошибках или страницы. Вот моя весенняя конфигурация.

Как заставить Spring вызвать мой обработчик отказа в доступе. Вот моя весенняя комплектация

 <security:http auto-config='true'>
    <security:intercept-url pattern="/static/**" filters="none"/>
    <security:intercept-url pattern="/login" filters="none"/>

      <security:intercept-url pattern="/**" access="ROLE_USER" />

      <security:form-login login-page="/index"
            default-target-url="/home" always-use-default-target="true"
            authentication-success-handler-ref="AuthenticationSuccessHandler"        
            login-processing-url="/j_spring_security_check" 
            authentication-failure-url="/index?error=true"/>

       <security:remember-me key="myLongSecretCookieKey" token-validity-seconds="1296000" 
            data-source-ref="jdbcDataSource" user-service-ref="AppUserDetailsService" />

       <security:access-denied-handler ref="myAccessDeniedHandler" />   

    </security:http>

    <bean id="myAccessDeniedHandler"
         class="web.exceptions.handlers.AccessDeniedExceptionHandler">
      <property name="errorPage" value="/public/403.htm" />
    </bean>

Пользовательский класс для обработки этого исключения приведен ниже

public class AccessDeniedExceptionHandler implements AccessDeniedHandler
{

    private String errorPage;

    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response,
            AccessDeniedException arg2) throws IOException, ServletException {
        response.sendRedirect(errorPage);
    }

       public void setErrorPage(String errorPage) {
       if ((errorPage != null) && !errorPage.startsWith("/")) {
            throw new IllegalArgumentException("errorPage must begin with '/'");
        }
        this.errorPage = errorPage;
    }

}

Когда я запускаю это приложение, я получаю эту ошибку. Я только вставляю часть трассировки стека и журналов Spring Debug.

20:39:46,173 DEBUG AffirmativeBased:53 - Voter: org.springframework.security.access.vote.RoleVoter@5b7da0d1, returned: -1
20:39:46,173 DEBUG AffirmativeBased:53 - Voter: org.springframework.security.access.vote.AuthenticatedVoter@14c92844, returned: 0
20:39:46,178 DEBUG ExceptionTranslationFilter:154 - Access is denied (user is anonymous); redirecting to authentication entry point
org.springframework.security.access.AccessDeniedException: Access is denied
    at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:71)
    at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:204)

Как мне исправить эту проблему? Во-первых, я хочу помешать Весне бросить это исключение. Если это все еще бросает это, я хочу обращаться с этим и не поднимать какие-либо флаги.

Обновление: я также приложил часть моего web.xml.

<!-- Hibernate filter configuration -->

<filter>
        <filter-name>HibernateFilter</filter-name>
        <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>HibernateFilter</filter-name> 
        <url-pattern>/*</url-pattern>       
        <dispatcher>FORWARD</dispatcher>
        <dispatcher>REQUEST</dispatcher>
    </filter-mapping>

<filter>
  <filter-name>springSecurityFilterChain</filter-name>
  <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
  <filter-name>springSecurityFilterChain</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

    <!--Dispatcher Servlet -->

   <servlet>
     <servlet-name>rowz</servlet-name>
     <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
     <load-on-startup>1</load-on-startup>
   </servlet>

Ответы [ 7 ]

12 голосов
/ 07 сентября 2011

В вашей конфигурации Вы требуете от пользователя всегда аутентификации при вводе любого URL на вашем сайте:

<security:intercept-url pattern="/**" access="ROLE_USER" />

Я думаю, вы должны разрешить пользователюбыть неаутентифицированным при входе на страницу входа :

<security:intercept-url pattern="/your-login-page-url" access="ROLE_ANONYMOUS" />
<security:intercept-url pattern="/your-login-process-url" access="ROLE_ANONYMOUS" />
<security:intercept-url pattern="/your-login-failure-url" access="ROLE_ANONYMOUS" />
<security:intercept-url pattern="/**" access="ROLE_USER" />

Если вы используете URL, такие как: /login/start, /login/error и /login/failure Вы можете иметь:

<security:intercept-url pattern="/login/**" access="ROLE_ANONYMOUS" />
<security:intercept-url pattern="/**" access="ROLE_USER" />

Обновление:

Наличие этой конфигурации должно сделать платформу для перенаправления всех неаутентифицированных (анонимных) пользователей на страницу входа и всех аутентифицированных на AccessDeniedHandler . AccessDeniedException является одной из основных частей платформы, и игнорирование ее не является хорошей идеей.Трудно помочь больше, если вы предоставляете только части конфигурации Spring Security.

Обязательно прочитайте JavaDoc для ExceptionTranslationFilter для подробного объяснения того, какие исключения генерируются платформой, почему икак обрабатываются по умолчанию.

Если возможно, попробуйте удалить как можно больше пользовательских частей, например AuthenticationSuccessHandler , RememberMeAuthenticationFilter и AccessDeniedHandler ипосмотреть, если проблема пессист?Постарайтесь получить минимальную согласованность и шаг за шагом добавьте новые функции, чтобы увидеть, откуда возникла ошибка.

Одна важная вещь, которую вы не упоминаете в своем вопросе, - что является результатом этого сообщения об ошибке?Вы получаете HTTP 500?Или HTTP 403?Или Вас перенаправляют на страницу входа в систему?

Если, как Вы упомянули в вопросе, пользователь не прошел проверку подлинности и его / ее перенаправляют на страницу входа в систему, чем он должен работать.Похоже, вы получаете сообщение об ошибке, зарегистрированное ExceptionTranslationFilter: 172 только потому, что для уровня DEBUG установлены классы Spring Security.Если это так, то это также то, как это должно работать, и если Вы не хотите, чтобы ошибка регистрировалась, тогда просто поднимите уровень регистрации для классов Spring Secyruty.

Обновление 2:

Шаблоны с filters="none" должны соответствовать атрибутам login-page, login-processing-url и authentication-failure-ur, установленным в <security:form-login />, чтобы пропустить все проверки SpringSecurity на страницах, которые отображают страницу входа и обрабатывают вход в систему.

<security:http auto-config='true'>
  <security:intercept-url pattern="/static/**" filters="none"/>
  <security:intercept-url pattern="/index" filters="none"/>
  <security:intercept-url pattern="/j_spring_security_check" filters="none"/>
  <security:intercept-url pattern="/**" access="ROLE_USER" />

  <security:form-login login-page="/index"
        default-target-url="/home" always-use-default-target="true"
        authentication-success-handler-ref="AuthenticationSuccessHandler"        
        login-processing-url="/j_spring_security_check" 
        authentication-failure-url="/index?error=true"/>

   <security:remember-me key="myLongSecretCookieKey" token-validity-seconds="1296000" 
        data-source-ref="jdbcDataSource" user-service-ref="AppUserDetailsService" />

   <security:access-denied-handler ref="myAccessDeniedHandler" />   

</security:http>
6 голосов
/ 25 мая 2013

AccessDeniedHandler вызывается, когда пользователь вошел в систему и нет прав доступа к ресурсу ( источник здесь ).Если вы хотите обработать запрос на странице входа в систему , когда пользователь не вошел в систему , просто настройте в security-context :

<http ... entry-point-ref="customAuthenticationEntryPoint">

И определите customAuthenticationEntryPoint:

<beans:bean id="customAuthenticationEntryPoint" class="pl.wsiadamy.webapp.controller.util.CustomAuthenticationEntryPoint">
</beans:bean>

СОВЕТ , не пытайтесь сражаться с ExceptionTranslationFilter.Я попытался переопределить org.springframework.security.web.access.ExceptionTranslationFilter без эффектов:

<beans:bean id="exceptionTranslationFilter" class="org.springframework.security.web.access.ExceptionTranslationFilter">
  <beans:property name="authenticationEntryPoint"  ref="customAuthenticationEntryPoint"/>
  <beans:property name="accessDeniedHandler" ref="accessDeniedHandler"/>
</beans:bean>
<beans:bean id="accessDeniedHandler"
 class="org.springframework.security.web.access.AccessDeniedHandlerImpl">
  <beans:property name="errorPage" value="/accessDenied.htm"/>
</beans:bean>

ref="customAuthenticationEntryPoint" просто не вызывался.

3 голосов
/ 10 сентября 2012

Я добавил страницу отказа в доступе Spring следующим образом: Работа каркаса пружины: 3.1 Spring Security: 3.1, Java 1.5 +

Запись в * -security.xml:

<security:access-denied-handler error-page="/<My Any error page controller name>" />

Пример:

<security:access-denied-handler error-page="/accessDeniedPage.htm" />

Страница ошибки всегда начинается с "/"

Запись для контроллера:

@Controller
public class RedirectAccessDenied {

    @RequestMapping(value = "/accessDeniedPage.htm", method = RequestMethod.GET)
    public String redirectAccessDenied(Model model) throws IOException, ServletException {
        System.out.println("############### Redirect Access Denied Handler!");
        return "403";
    }
}

Здесь 403 - мое имя JSP.

2 голосов
/ 09 сентября 2011

Spring Security использует объект AuthenticationEntryPoint, чтобы решить, что делать, когда пользователю требуется аутентификация.Вы можете создать свой собственный компонент AuthenticationEntryPoint ( см. Javadoc ), а затем установить атрибут entryPoint в элементе http:

<http entry-point-ref="entryPointBean" .... />

Однако по умолчанию элемент form-login создаетLoginUrlAuthenticationEntryPoint, который перенаправляет всех ваших неаутентифицированных пользователей на страницу входа, поэтому вам не нужно делать это самостоятельно.На самом деле в опубликованном вами журнале утверждается, что он перенаправляет пользователя на точку входа аутентификации: «Доступ запрещен (пользователь анонимный); перенаправление на точку входа аутентификации».

Интересно, проблема в том, что вы отключили цепочку фильтров для URL входа?Вместо того, чтобы устанавливать фильтры на «Нет», что означает, что безопасность пружины полностью обойдена, попробуйте оставить фильтры включенными, но разрешить неограниченный доступ, как показано ниже:

<security:intercept-url pattern="/login" access="permitAll" />

Если это по-прежнему не помогает, пожалуйста, оставьте остальныевойдите в систему, чтобы мы могли видеть, что происходит после передачи запроса в точку входа.

1 голос
/ 21 января 2016

Программно решение:

@Order(1)
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    //
    // ...
    //

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.exceptionHandling().accessDeniedHandler(new AccessDeniedHandlerImpl() {
            @Override
            public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
                super.handle(request, response, accessDeniedException);
                accessDeniedException.printStackTrace();
            }
        });

        //
        // ...
        //

    }

}
0 голосов
/ 09 сентября 2011

Похоже, что Spring пытается перенаправить пользователей, которые не вошли на страницу входа, которая является "/ index", но сама по себе является защищенным URL.

Другая возможность состоит в том, что она пытаетсяотобразить /public/403.html, но это снова защищено конфигурацией безопасности.

Можете ли вы добавить следующие записи и попробовать?

<security:intercept-url pattern="/login" filters="none" />
<security:intercept-url pattern="/public/**" filters="none" />
0 голосов
/ 04 сентября 2011

Можете ли вы проверить, поддерживает ли ваш web.xml запрос пересылки?

errorPage - это запрос FORWARD, и в основном в файле web.xml мы поддерживаем только REDIRECTS.Просто мысль, что твой код выглядит нормально для меня.

Отредактировано

Другая точка зрения, и это взято только из рабочего кода.Взгляните на Аутентифицированный класс избирателя

Отключите аннотации

<global-method-security pre-post-annotations="disabled"
    secured-annotations="disabled" access-decision-manager-ref="accessDecisionManager">
</global-method-security>

в обход фильтров

<http auto-config="true" use-expressions="true"
    access-decision-manager-ref="accessDecisionManager"
    access-denied-page="/accessDenied">
    <intercept-url pattern="/appsecurity/login.jsp" filters="none" />
    <intercept-url pattern="/changePassword" filters="none" />
    <intercept-url pattern="/pageNotFound" filters="none" />
    <intercept-url pattern="/accessDenied" filters="none" />
    <intercept-url pattern="/forgotPassword" filters="none" />
    <intercept-url pattern="/**" filters="none" />


    <form-login login-processing-url="/j_spring_security_check"
        default-target-url="/home" login-page="/loginDetails"
        authentication-failure-handler-ref="authenticationExceptionHandler"
        authentication-failure-url="/?login_error=t" />
    <logout logout-url="/j_spring_security_logout"
        invalidate-session="true" logout-success-url="/" />
    <remember-me />
    <!-- Uncomment to limit the number of sessions a user can have -->
    <session-management invalid-session-url="/">
        <concurrency-control max-sessions="1"
            error-if-maximum-exceeded="true" />
    </session-management>
</http>

Настраиваемое решение Voter

<bean id="customVoter" class="xyz.appsecurity.helper.CustomDecisionVoter" />

Access Decision Manager

<!-- Define AccessDesisionManager as UnanimousBased -->
<bean id="accessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased">
    <property name="decisionVoters">
        <list>
            <ref bean="customVoter" />
            <!-- <bean class="org.springframework.security.access.vote.RoleVoter" 
                /> -->
            <bean class="org.springframework.security.access.vote.AuthenticatedVoter" />
        </list>
    </property>
</bean>

Обработчик исключений аутентификации

<bean id="authenticationExceptionHandler"
    class="org.springframework.security.web.authentication.ExceptionMappingAuthenticationFailureHandler">
    <property name="exceptionMappings">
        <props>
            <!-- /error.jsp -->
            <prop
                key="org.springframework.security.authentication.BadCredentialsException">/?login_error=t</prop>
            <!-- /getnewpassword.jsp -->
            <prop
                key="org.springframework.security.authentication.CredentialsExpiredException">/changePassword</prop>
            <!-- /lockedoutpage.jsp -->
            <prop key="org.springframework.security.authentication.LockedException">/?login_error=t</prop>
            <!-- /unauthorizeduser.jsp -->
            <prop
                key="org.springframework.security.authentication.DisabledException">/?login_error=t</prop>
        </props>
    </property>
</bean>
...