programing

세션 없이 Spring Security를 사용하려면 어떻게 해야 하나요?

abcjava 2023. 2. 25. 19:30
반응형

세션 없이 Spring Security를 사용하려면 어떻게 해야 하나요?

Amazon EC2에 상주하며 Amazon의 Elastic Load Balancers를 사용하는 Spring Security로 웹 어플리케이션을 구축하고 있습니다.안타깝게도 ELB는 스틱세션을 지원하지 않기 때문에 세션 없이 어플리케이션이 정상적으로 동작하도록 해야 합니다.

지금까지는 쿠키를 통해 토큰을 할당하도록 Remember Me Services를 설정했습니다.이 작업은 정상적으로 진행되지만 쿠키가 브라우저 세션과 함께 만료되도록 합니다(예: 브라우저가 닫힐 때).

세션 없이 스프링 시큐리티를 이용하고 싶은 건 저뿐만이 아닙니다좋은 의견이라도 있나?

Java Config를 사용하는 Spring Security 3에서는 Http Security를 사용할 수 있습니다.session Management():

@Override
protected void configure(final HttpSecurity http) throws Exception {
    http
        .sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}

오늘 같은 문제(SecurityContextPersistenceFilter에 커스텀SecurityContextRepository 삽입)로 4~5시간 작업했습니다.드디어 알아냈어먼저 Spring Security ref. doc 섹션 8.3에는 SecurityContextPersistenceFilter bean 정의가 있습니다.

<bean id="securityContextPersistenceFilter" class="org.springframework.security.web.context.SecurityContextPersistenceFilter">
    <property name='securityContextRepository'>
        <bean class='org.springframework.security.web.context.HttpSessionSecurityContextRepository'>
            <property name='allowSessionCreation' value='false' />
        </bean>
    </property>
</bean>

그리고 이 정의 뒤에는 다음과 같은 설명이 있습니다."또는 SecurityContextRepository 인터페이스의 늘 구현을 제공할 수 있습니다.이것에 의해, 요구중에 세션이 이미 작성되어 있는 경우에서도, 시큐러티 콘텍스트의 보존이 방지됩니다."

SecurityContextPersistenceFilter에 커스텀 SecurityContextRepository를 삽입해야 했습니다.그래서 위의 bean 정의를 커스텀 인크루트로 변경하여 보안 컨텍스트에 넣기만 하면 됩니다.

응용 프로그램을 실행할 때 로그를 추적한 결과 SecurityContextPersistenceFilter가 커스텀내용을 사용하지 않고 HttpSessionSecurityContextRepository를 사용하고 있었습니다.

그 밖에도 몇 가지 작업을 시도한 결과, 커스텀 Security Context Repository에 "http" 네임스페이스의 "security-context-rep" 속성을 지정해야 한다는 것을 알게 되었습니다."http" 네임스페이스를 사용하여 자체 SecurityContextRepository include를 삽입하는 경우 "security-context-repository-ref" 속성을 사용해 보십시오.

"http" 네임스페이스를 사용하면 별도의 SecurityContextPersistenceFilter 정의는 무시됩니다.위에서 복사한 바와 같이 참조 문서에는 기재되어 있지 않습니다.

제가 잘못 이해했다면 정정해 주세요.

Spring Securitiy 3.0에서는 더 쉬워 보입니다.네임스페이스 구성을 사용하는 경우 다음과 같이 간단히 수행할 수 있습니다.

<http create-session="never">
  <!-- config -->
</http>

또는 Security Context Repository를 늘로 설정할 수도 있습니다.이렇게 하면 아무것도 저장되지 않습니다.

, 그럼 ㄴㄴㄴ데를 한 번 보세요.SecurityContextPersistenceFilter, , , 수업, 수업, 수업, 수업, 수업, 수업, 수업, 수업, 수업.그은 、 떻게 、SecurityContextHolder을 사용하다로는 「」를 사용합니다.HttpSessionSecurityContextRepositoryhttp를 사용합니다.

으로 꽤 .SecurityContextRepository.

「 」를 .securityContext.xml이하에 나타냅니다.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:sec="http://www.springframework.org/schema/security"
       xmlns:jee="http://www.springframework.org/schema/jee"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
       http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd
       http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd">

    <context:annotation-config/>

    <sec:global-method-security secured-annotations="enabled" pre-post-annotations="enabled"/>

    <bean id="securityContextRepository" class="com.project.server.security.TokenSecurityContextRepository"/>

    <bean id="securityContextFilter" class="com.project.server.security.TokenSecurityContextPersistenceFilter">
        <property name="repository" ref="securityContextRepository"/>
    </bean>

    <bean id="logoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter">
        <constructor-arg value="/login.jsp"/>
        <constructor-arg>
            <list>
                <bean class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"/>
            </list>
        </constructor-arg>
    </bean>

    <bean id="formLoginFilter"
          class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
        <property name="authenticationManager" ref="authenticationManager"/>
        <property name="authenticationSuccessHandler">
            <bean class="com.project.server.security.TokenAuthenticationSuccessHandler">
                <property name="defaultTargetUrl" value="/index.html"/>
                <property name="passwordExpiredUrl" value="/changePassword.jsp"/>
                <property name="alwaysUseDefaultTargetUrl" value="true"/>
            </bean>
        </property>
        <property name="authenticationFailureHandler">
            <bean class="com.project.server.modules.security.CustomUrlAuthenticationFailureHandler">
                <property name="defaultFailureUrl" value="/login.jsp?failure=1"/>
            </bean>
        </property>
        <property name="filterProcessesUrl" value="/j_spring_security_check"/>
        <property name="allowSessionCreation" value="false"/>
    </bean>

    <bean id="servletApiFilter"
          class="org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter"/>

    <bean id="anonFilter" class="org.springframework.security.web.authentication.AnonymousAuthenticationFilter">
        <property name="key" value="ClientApplication"/>
        <property name="userAttribute" value="anonymousUser,ROLE_ANONYMOUS"/>
    </bean>


    <bean id="exceptionTranslator" class="org.springframework.security.web.access.ExceptionTranslationFilter">
        <property name="authenticationEntryPoint">
            <bean class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
                <property name="loginFormUrl" value="/login.jsp"/>
            </bean>
        </property>
        <property name="accessDeniedHandler">
            <bean class="org.springframework.security.web.access.AccessDeniedHandlerImpl">
                <property name="errorPage" value="/login.jsp?failure=2"/>
            </bean>
        </property>
        <property name="requestCache">
            <bean id="nullRequestCache" class="org.springframework.security.web.savedrequest.NullRequestCache"/>
        </property>
    </bean>

    <alias name="filterChainProxy" alias="springSecurityFilterChain"/>

    <bean id="filterChainProxy" class="org.springframework.security.web.FilterChainProxy">
        <sec:filter-chain-map path-type="ant">
            <sec:filter-chain pattern="/**"
                              filters="securityContextFilter, logoutFilter, formLoginFilter,
                                        servletApiFilter, anonFilter, exceptionTranslator, filterSecurityInterceptor"/>
        </sec:filter-chain-map>
    </bean>

    <bean id="filterSecurityInterceptor"
          class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
        <property name="securityMetadataSource">
            <sec:filter-security-metadata-source use-expressions="true">
                <sec:intercept-url pattern="/staticresources/**" access="permitAll"/>
                <sec:intercept-url pattern="/index.html*" access="hasRole('USER_ROLE')"/>
                <sec:intercept-url pattern="/rpc/*" access="hasRole('USER_ROLE')"/>
                <sec:intercept-url pattern="/**" access="permitAll"/>
            </sec:filter-security-metadata-source>
        </property>
        <property name="authenticationManager" ref="authenticationManager"/>
        <property name="accessDecisionManager" ref="accessDecisionManager"/>
    </bean>

    <bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
        <property name="decisionVoters">
            <list>
                <bean class="org.springframework.security.access.vote.RoleVoter"/>
                <bean class="org.springframework.security.web.access.expression.WebExpressionVoter"/>
            </list>
        </property>
    </bean>

    <bean id="authenticationManager" class="org.springframework.security.authentication.ProviderManager">
        <property name="providers">
            <list>
                <bean name="authenticationProvider"
                      class="com.project.server.modules.security.oracle.StoredProcedureBasedAuthenticationProviderImpl">
                    <property name="dataSource" ref="serverDataSource"/>
                    <property name="userDetailsService" ref="userDetailsService"/>
                    <property name="auditLogin" value="true"/>
                    <property name="postAuthenticationChecks" ref="customPostAuthenticationChecks"/>
                </bean>
            </list>
        </property>
    </bean>

    <bean id="customPostAuthenticationChecks" class="com.project.server.modules.security.CustomPostAuthenticationChecks"/>

    <bean name="userDetailsService" class="com.project.server.modules.security.oracle.UserDetailsServiceImpl">
        <property name="dataSource" ref="serverDataSource"/>
    </bean>

</beans>

★★★★★★★★★★★★★★★★★.create-session="never"완전히 무국적자가 되는 것은 아닙니다.Spring Security 이슈 관리에 문제가 있습니다.

편집: Spring Security 3.1에서는STATELESS이 모든 것 대신 사용할 수 있는 옵션입니다.이치노원래의 대답은 후세를 위해 아래에 보관되어 있다.

되어 있는 한 후, 이 답변에 기재되어 있는 것을 할 때 .<http>네임스페이스 구성, 드디어 내 사용 사례에 맞는 접근 방식을 찾았습니다.Spring Security가 세션을 시작하지 않도록(어플리케이션의 다른 부분에서 세션을 사용하기 때문에) 세션에서 인증을 전혀 "기억"하지 않도록 할 필요는 없습니다(모든 요청을 다시 확인해야 합니다).

우선 위에서 설명한 '늘 구현' 기술을 어떻게 해야 하는지 알 수 없었습니다. Context 를 security Context Repository로 .null노옵전자는 기능하지 않습니다. 왜냐하면NullPointerExceptionSecurityContextPersistenceFilter.doFilter()는 상상할수 no-op 실장은 no-op 실장입니다.

public class NullSpringSecurityContextRepository implements SecurityContextRepository {

    @Override
    public SecurityContext loadContext(final HttpRequestResponseHolder requestResponseHolder_) {
        return SecurityContextHolder.createEmptyContext();
    }

    @Override
    public void saveContext(final SecurityContext context_, final HttpServletRequest request_,
            final HttpServletResponse response_) {
    }

    @Override
    public boolean containsContext(final HttpServletRequest request_) {
        return false;
    }

}

한 일이 내는 이 않는다.왜냐하면 이상한 점이 있기 때문이다.ClassCastException 관한 일response_discloss.discloss.

중에 , 에에 그 .<http>간단하게 할 수 .SECURITY_CONTEXT_FILTER위치(문서 참조해 주세요)내가 찾은 유일한 방법은SecurityContextPersistenceFilter 거였어요.ApplicationContextAware콩:

public class SpringSecuritySessionDisabler implements ApplicationContextAware {

    private final Logger logger = LoggerFactory.getLogger(SpringSecuritySessionDisabler.class);

    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(final ApplicationContext applicationContext_) throws BeansException {
        applicationContext = applicationContext_;
    }

    public void disableSpringSecuritySessions() {
        final Map<String, FilterChainProxy> filterChainProxies = applicationContext
                .getBeansOfType(FilterChainProxy.class);
        for (final Entry<String, FilterChainProxy> filterChainProxyBeanEntry : filterChainProxies.entrySet()) {
            for (final Entry<String, List<Filter>> filterChainMapEntry : filterChainProxyBeanEntry.getValue()
                    .getFilterChainMap().entrySet()) {
                final List<Filter> filterList = filterChainMapEntry.getValue();
                if (filterList.size() > 0) {
                    for (final Filter filter : filterList) {
                        if (filter instanceof SecurityContextPersistenceFilter) {
                            logger.info(
                                    "Found SecurityContextPersistenceFilter, mapped to URL '{}' in the FilterChainProxy bean named '{}', setting its securityContextRepository to the null implementation to disable caching of authentication",
                                    filterChainMapEntry.getKey(), filterChainProxyBeanEntry.getKey());
                            ((SecurityContextPersistenceFilter) filter).setSecurityContextRepository(
                             new NullSpringSecurityContextRepository());
                        }
                    }
                }

            }
        }
    }
}

어쨌든, 매우 해킹적이긴 하지만 실제로 효과가 있는 해결책으로요.간단히 사용하다Filter세션 엔트리를 삭제합니다.HttpSessionSecurityContextRepository는, 동작하는 타이밍을 찾습니다.

public class SpringSecuritySessionDeletingFilter extends GenericFilterBean implements Filter {

    @Override
    public void doFilter(final ServletRequest request_, final ServletResponse response_, final FilterChain chain_)
            throws IOException, ServletException {
        final HttpServletRequest servletRequest = (HttpServletRequest) request_;
        final HttpSession session = servletRequest.getSession();
        if (session.getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY) != null) {
            session.removeAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY);
        }

        chain_.doFilter(request_, response_);
    }
}

다음에, 설정에서는 다음과 같이 합니다.

<bean id="springSecuritySessionDeletingFilter"
    class="SpringSecuritySessionDeletingFilter" />

<sec:http auto-config="false" create-session="never"
    entry-point-ref="authEntryPoint">
    <sec:intercept-url pattern="/**"
        access="IS_AUTHENTICATED_REMEMBERED" />
    <sec:intercept-url pattern="/static/**" filters="none" />
    <sec:custom-filter ref="myLoginFilterChain"
        position="FORM_LOGIN_FILTER" />

    <sec:custom-filter ref="springSecuritySessionDeletingFilter"
        before="SECURITY_CONTEXT_FILTER" />
</sec:http>

간단한 메모: "create-sessions"가 아니라 "create-session"입니다.

작성 및 삭제

HTTP 세션의 작성 순서를 제어합니다.

설정되지 않은 경우 기본값은 "ifRequired"입니다.다른 옵션은 "항상"과 "절대"입니다.

이 특성의 설정은 HttpSessionContext IntegrationFilter의 allowSessionCreation 및 forceEagerSessionCreation 속성에 영향을 줍니다.이 특성의 설정이 "never"로 설정되어 있지 않으면 allowSessionCreation은 항상 true가 됩니다.forceEagerSessionCreation이 "always"로 설정되어 있지 않으면 "false"가 됩니다.

따라서 기본 설정에서는 세션 생성이 허용되지만 강제로 생성되지는 않습니다.예외는 동시 세션 제어를 사용하도록 설정한 경우 여기서의 설정에 관계없이 forceEagerSessionCreation이 true로 설정됩니다."never"를 사용하면 Http Session Context Integration Filter 초기화 중에 예외가 발생합니다.

세션 사용방법에 대한 자세한 내용은 Http Session Security Context Repository javadoc에 기재되어 있습니다.

2016년부터는 ELB가 스틱세션을 지원하게 될 것 같습니다.또한 세션을 Redis에 저장할 수도 있습니다.

언급URL : https://stackoverflow.com/questions/2504590/how-can-i-use-spring-security-without-sessions

반응형