Подтвердить что ты не робот

Spring 3 Безопасность: AccessDeniedHandler не вызывается

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

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

Как мне получить spring для вызова моего обработчика отказа доступа. Вот моя конфигурация 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;
    }

}

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

20:39:46,173 DEBUG AffirmativeBased:53 - Voter: [email protected], returned: -1
20:39:46,173 DEBUG AffirmativeBased:53 - Voter: org.springframework.security.acce[email protected], 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)

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

Обновление: я также добавил часть моего 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>
4b9b3361

Ответ 1

В вашей конфигурации вам нужно, чтобы пользователь был всегда аутентифицирован при вводе любого 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" />

Update:

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

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

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

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

Если, как вы упомянули в вопросе, пользователь не аутентифицирован, и он/она перенаправляется на страницу входа в систему, а не то, как он намеревался работать. Похоже, вы получили сообщение об ошибке, зарегистрированное ExceptionTranslationFilter: 172, только потому, что у вас установлен уровень DEBUG на Spring классы безопасности. Если это так, то и то, как оно предназначено для работы, и если вы не хотите, чтобы ошибка регистрировалась, а не просто повышайте уровень ведения журнала для классов 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>

Ответ 2

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

<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

Я добавил страницу Spring Доступ запрещен в следующем порядке: Spring Работа рамы: 3.1 Spring Безопасность: 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.

Ответ 4

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

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

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

Интересно, проблема в том, что вы отключили цепочку фильтров для URL-адреса входа. Вместо того, чтобы устанавливать фильтры в none, что означает, что защита spring полностью исключена, попробуйте включить фильтры, но разрешите неограниченный доступ следующим образом:

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

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

Ответ 5

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

@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();
            }
        });

        //
        // ...
        //

    }

}

Ответ 6

Вы можете проверить, что ваш web.xml поддерживает запрос вперед?

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

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

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

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

<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>

пользовательский выборщик решений

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

Диспетчер решений доступа

<!-- 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>

Ответ 7

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

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

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

<security:intercept-url pattern="/login" filters="none" />
<security:intercept-url pattern="/public/**" filters="none" />