Безопасность пружины Grails: перенаправление перенапряжения auth [дубликат]

Не то, чтобы сами синглтоны были плохи, но шаблон дизайна GoF. Единственный действительный аргумент, который справедлив, заключается в том, что шаблон проектирования GoF не поддается тестированию, особенно если тесты выполняются параллельно.

Использование одного экземпляра класса является допустимой конструкцией как если вы применяете в коде следующие средства:

  1. Убедитесь, что класс, который будет использоваться как одноэлементный, реализует интерфейс. Это позволяет реализовать заглушки или макеты с использованием того же интерфейса
  2. Убедитесь, что Singleton является потокобезопасным. Это заданное.
  3. Синглтон должен быть простым по своей природе и не слишком сложным.
  4. Во время выполнения вашего приложения, где нужно передать одноточие в данный объект, используйте класса, который создает этот объект и имеет фабрику классов, передающую экземпляр singleton классу, который ему нужен.
  5. Во время тестирования и обеспечения детерминированного поведения создайте одиночный экземпляр как отдельный экземпляр как сам фактический класс или stub / mock, который реализует свое поведение и передает его, как и классу, который этого требует. Не используйте фактор класса, который создает этот объект под тестом, который нуждается в синглтоне во время теста, поскольку он пройдет один глобальный экземпляр, который побеждает цель.

Мы использовали Синглтоны в наших решениях с большим успехом, которые можно проверить, обеспечивая детерминированное поведение в параллельных потоках тестового запуска.

0
задан Code Junkie 7 March 2016 в 22:05
поделиться

2 ответа

Я столкнулся с подобной проблемой и применил фильтр в цепочке фильтров для обнаружения запросов AJAX и ответа с настроенным статусом HTTP (вы можете изменить его на 401, если хотите).

В принципе, есть три части. Во-первых, это фильтр. Это фильтр сервлетов и проверяет запрос, а также состояние аутентификации в сеансе. Во-вторых, определение фильтра как компонента в контексте приложения в Resources.groovy. Наконец, вставив его в цепочку фильтров Spring Security, которую я сделал в Bootstrap.groovy.

Я проведу вас через это.

Сначала фильтр сервлета (в src / java)

package com.xyz.security;

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.authentication.AuthenticationTrustResolver;
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.util.ThrowableAnalyzer;
import org.springframework.security.web.util.ThrowableCauseExtractor;
import org.springframework.web.filter.GenericFilterBean;

public class AjaxTimeoutRedirectFilter extends GenericFilterBean {

    // private static final Logger logger =
    // LoggerFactory.getLogger(AjaxTimeoutRedirectFilter.class);

    private ThrowableAnalyzer throwableAnalyzer = new DefaultThrowableAnalyzer();
    private AuthenticationTrustResolver authenticationTrustResolver = new AuthenticationTrustResolverImpl();

    private int customSessionExpiredErrorCode = 901;

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        try {
            chain.doFilter(request, response);

            // logger.debug("Chain processed normally");
        } catch (IOException ex) {
            throw ex;
        } catch (Exception ex) {
            Throwable[] causeChain = throwableAnalyzer.determineCauseChain(ex);
            RuntimeException ase = (AuthenticationException) throwableAnalyzer
                    .getFirstThrowableOfType(AuthenticationException.class,
                            causeChain);

            if (ase == null) {
                ase = (AccessDeniedException) throwableAnalyzer
                        .getFirstThrowableOfType(AccessDeniedException.class,
                                causeChain);
            }

            if (ase != null) {
                if (ase instanceof AuthenticationException) {
                    throw ase;
                } else if (ase instanceof AccessDeniedException) {

                    if (authenticationTrustResolver
                            .isAnonymous(SecurityContextHolder.getContext()
                                    .getAuthentication())) {
                        // logger.info("User session expired or not logged in yet");
                        String ajaxHeader = ((HttpServletRequest) request)
                                .getHeader("X-Requested-With");

                        if ("XMLHttpRequest".equals(ajaxHeader)) {
                            // logger.info("Ajax call detected, send {} error code",
                            // this.customSessionExpiredErrorCode);
                            HttpServletResponse resp = (HttpServletResponse) response;
                            resp.sendError(this.customSessionExpiredErrorCode);
                        } else {
                            // logger.info("Redirect to login page");
                            throw ase;
                        }
                    } else {
                        throw ase;
                    }
                }
            }

        }
    }

    private static final class DefaultThrowableAnalyzer extends
            ThrowableAnalyzer {
        /**
         * @see org.springframework.security.web.util.ThrowableAnalyzer#initExtractorMap()
         */
        protected void initExtractorMap() {
            super.initExtractorMap();

            registerExtractor(ServletException.class,
                    new ThrowableCauseExtractor() {
                        public Throwable extractCause(Throwable throwable) {
                            ThrowableAnalyzer.verifyThrowableHierarchy(
                                    throwable, ServletException.class);
                            return ((ServletException) throwable)
                                    .getRootCause();
                        }
                    });
        }

    }

    public void setCustomSessionExpiredErrorCode(
            int customSessionExpiredErrorCode) {
        this.customSessionExpiredErrorCode = customSessionExpiredErrorCode;
    }
}

Во-вторых, определение фильтра как компонента в контексте приложения в Resources.groovy

beans = {
    ajaxTimeoutRedirectFilter(com.xyz.security.AjaxTimeoutRedirectFilter)
}

И, наконец, получение фильтра в Spring Security (я использовал BootStrap.groovy для этого)

import grails.plugin.springsecurity.SecurityFilterPosition
import grails.plugin.springsecurity.SpringSecurityUtils
class BootStrap {

    def init = { servletContext ->

        SpringSecurityUtils.clientRegisterFilter('ajaxTimeoutRedirectFilter', SecurityFilterPosition.EXCEPTION_TRANSLATION_FILTER.order + 10)

    }
    def destroy = {
    }
}
1
ответ дан Joshua Moore 18 August 2018 в 12:48
поделиться

Вы считали «блокировку экрана», когда пользователь не работает на стороне клиента? Конечно, вы должны обрабатывать конец сеанса на стороне сервера, но на самом деле это кажется более чистым и более безопасным решением, чем ожидание действия с клиентской стороны (особенно если пользователь ушел и оставил на экране некоторые конфиденциальные данные).

Проверьте эту директиву ng-idle .

0
ответ дан Michal_Szulc 18 August 2018 в 12:48
поделиться
Другие вопросы по тегам:

Похожие вопросы: