spring-web项目采用token认证session创建过多导致OOM

本文介绍关于session过多,分问题、解决方案、分析在另写文章。

问题:spring-boot微服务互相调用时,采用的是spring-security来认证,比如A服务调用B服务用feign调用方式。

1. 浏览器访问web项目,传递token,Bearer 0d8c2dfa-5a3f-4fde-935e-96da27712687,此时,web服务会拿着token,去用户服务认证,认证通过,放行。每次访问都会在web服务创建一个新的session,有效期是30分钟,即使前端下次访问的时候,传递上次响应的session,web服务也会创建一个新的,这样在短时间内有大量请求时,就会创建大量的session,并且不会回收,就造成OOM。

下载dump文件,用jprofiler分析如图

可以看到session的数量非常多。

解决方案:

在配置http的时候采用固定的session策略:

http.sessionManagement().sessionFixation().none();

完整代码



import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;

import javax.servlet.http.HttpServletResponse;


@Configuration
@EnableResourceServer
@ConditionalOnProperty(prefix = "spring.security.oauth2", name = "enabled", havingValue = "true", matchIfMissing = true)
public class OAuth2ResourceServer extends ResourceServerConfigurerAdapter {

    @Value("${spring.application.name}")
    private String resourceId;

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) {
        resources.resourceId(resourceId);
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
            .exceptionHandling()
            .authenticationEntryPoint((request, response, authException) -> response
                .sendError(HttpServletResponse.SC_UNAUTHORIZED))
            .and()
            .authorizeRequests()
            // 填写不需要token即可调用的接口的路径
            .antMatchers(
                "/v2/api-docs",
                "/favicon.ico",
                "/webjars/**",
                "/csrf",
                "/swagger**",
                "/swagger-resources/**",
                "/course/coursebase/**",
                "/hystrix**",
                "/hystrix/**",
                "/proxy.stream",
                "/actuator/**",
                "/actuator",
                "/cache",
                "/webservices/**")
            .permitAll()
            .anyRequest()
            .authenticated()
            .and()
            //这里配置也可以,下面单独配置也行
            .sessionManagement()
            .sessionFixation()
            .none()
            .and()
            
            .httpBasic();
        //.maximumSessions(30)   最大的session数量
// 采用固定session
//        http.sessionManagement().sessionFixation().none();
//采用合并session,每次都会创建新的,并且把原来session的属性复制到新的里面,原来的session过期,也会创建大量的session
//        http.sessionManagement().sessionFixation().migrateSession();

    }

}

分析在下一篇文章,介绍session管理过滤器,如何创建。

服务之间调用,也会产生大量的session,B服务采用request域,不创建session。



import java.util.Map;
import javax.annotation.Resource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.security.oauth2.client.DefaultOAuth2ClientContext;
import org.springframework.security.oauth2.client.OAuth2ClientContext;
import org.springframework.security.oauth2.client.filter.OAuth2ClientContextFilter;
import org.springframework.security.oauth2.client.token.AccessTokenRequest;
import org.springframework.security.oauth2.client.token.DefaultAccessTokenRequest;

@Configuration
@ConditionalOnProperty(
    name = {"my.scope.request"},
    havingValue = "true"
)
public class LeadingOAuth2ClientConfiguration {
    public LeadingOAuth2ClientConfiguration() {
    }

    @Bean
    public OAuth2ClientContextFilter oauth2ClientContextFilter() {
        OAuth2ClientContextFilter filter = new OAuth2ClientContextFilter();
        return filter;
    }

    @Bean
    @Scope(
        value = "request",
        proxyMode = ScopedProxyMode.INTERFACES
    )
    protected AccessTokenRequest accessTokenRequest(@Value("#{request.parameterMap}") Map<String, String[]> parameters, @Value("#{request.getAttribute('currentUri')}") String currentUri) {
        DefaultAccessTokenRequest request = new DefaultAccessTokenRequest(parameters);
        request.setCurrentUri(currentUri);
        return request;
    }

    @Configuration
    @ConditionalOnProperty(
        name = {"my.scope.request"},
        havingValue = "true"
    )
    protected static class OAuth2ClientContextConfiguration {
        @Resource
        @Qualifier("accessTokenRequest")
        private AccessTokenRequest accessTokenRequest;

        protected OAuth2ClientContextConfiguration() {
        }

        @Bean
        @Scope(
            value = "request",
            proxyMode = ScopedProxyMode.INTERFACES
        )
        public OAuth2ClientContext oauth2ClientContext() {
            return new DefaultOAuth2ClientContext(this.accessTokenRequest);
        }
    }
}

在yml中配置 my.scope.request=true 

session在服务之间共享,服务调用传递session,也可以。

参考文章

这篇session回话写的不错

SpringSecurity(九): 自定义Session 会话超时处理逻辑 - 西门夜说 - 博客园

关于feign调用时,session丢失的解决方案 - 程序员大本营

Spring,无法在Java配置中更改SessionAuthenticationStrategy-Java 学习之路

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值