[11] SessionManagementFilter

本文深入解析SessionManagementFilter的工作原理,包括防止session-fixation攻击的机制,以及如何通过配置SessionCreationPolicy来控制session的创建。文章详细分析了代码执行流程,探讨了SessionAuthenticationStrategy和SecurityContextRepository的作用。

SessionManagementFilter

介绍

该Filter的主要作用是,当请求经过过滤器是 ,判断缓存中是否有同一session id的请求,如果不存在则从上下文中获取身份认证信息,并使用SessionAuthenticationStrategy对身份认证信息执行必要的操作,比如重新生成session id来防止session-fixation攻击。过滤器中有2个比较重要的全局变量,分别是SessionAuthenticationStrategy、SecurityContextRepository。SessionAuthenticationStrategy实例的实现是CompositeSessionAuthenticationStrategy,是一个复合型的会话认证策略,默认情况下仅包含一个ChangeSessionIdAuthenticationStrategy,用于改变session的id,可以防止session fixation攻击(建议百度)。SecurityContextRepository用户将SecurityContext上下文保存到session中,但是默认情况SecurityContextRepository的实现是NullSecurityContextRepository,可以通过修改配置为SessionCreationPolicy.IF_REQUIRED,进而给Filter注入HttpSessionSecurityContextRepository的实现,具体如何进行配置以及配置注入的代码分析可以参照SecurityContextPersistenceFilter这篇文章。

代码分析

步骤1

当请求经过SessionManagementFilter时,需要判断缓存中是否已经存在了同一session id的请求了,只有不存在时,才从上下文中取身份认证信息,并通过SessionAuthenticationStrategy对authentication进行认证操作,认证成功后写入到缓存中,代码如下:

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
        throws IOException, ServletException {
   
   
    HttpServletRequest request = (HttpServletRequest) req;
    HttpServletResponse response = (HttpServletResponse) res;
	//过滤器已经应用过了,直接可以进入下个过滤器
    if (request.getAttribute(FILTER_APPLIED) != null) {
   
   
        chain.doFilter(request, response);
        return;
    }
	//防止重复进入验证代码,先打个标识
    request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
	//判断repo中是否未存储过同一session id请求
    if (!securityContextRepository.containsContext(request)) {
   
   
        //从上下文中或身份认证信息
        Authentication authentication = SecurityContextHolder.getContext()
                .getAuthentication();
		//身份认证信息非空,并且不是匿名认证
        if (authentication != null && !trustResolver.isAnonymous(authentication)) {
   
   
            
2025-11-05 15:19:23.442 [main] INFO o.w.a.web.api.WebApiApplication - Starting WebApiApplication using Java 17.0.16 with PID 24352 (D:\world_aquatics_0922\world-aquatics-api\world-aquatics-web-api\target\classes started by LZY in D:\world_aquatics_0922) 2025-11-05 15:19:23.444 [main] INFO o.w.a.web.api.WebApiApplication - No active profile set, falling back to 1 default profile: "default" 2025-11-05 15:19:25.147 [main] INFO o.s.d.r.c.RepositoryConfigurationDelegate - Multiple Spring Data modules found, entering strict repository configuration mode 2025-11-05 15:19:25.149 [main] INFO o.s.d.r.c.RepositoryConfigurationDelegate - Bootstrapping Spring Data Elasticsearch repositories in DEFAULT mode. 2025-11-05 15:19:25.166 [main] INFO o.s.d.r.c.RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 13 ms. Found 0 Elasticsearch repository interfaces. 2025-11-05 15:19:25.171 [main] INFO o.s.d.r.c.RepositoryConfigurationDelegate - Multiple Spring Data modules found, entering strict repository configuration mode 2025-11-05 15:19:25.171 [main] INFO o.s.d.r.c.RepositoryConfigurationDelegate - Bootstrapping Spring Data Reactive Elasticsearch repositories in DEFAULT mode. 2025-11-05 15:19:25.173 [main] INFO o.s.d.r.c.RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 1 ms. Found 0 Reactive Elasticsearch repository interfaces. 2025-11-05 15:19:25.183 [main] INFO o.s.d.r.c.RepositoryConfigurationDelegate - Multiple Spring Data modules found, entering strict repository configuration mode 2025-11-05 15:19:25.184 [main] INFO o.s.d.r.c.RepositoryConfigurationDelegate - Bootstrapping Spring Data Redis repositories in DEFAULT mode. 2025-11-05 15:19:25.192 [main] INFO o.s.d.r.c.RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 1 ms. Found 0 Redis repository interfaces. 2025-11-05 15:19:25.879 [main] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat initialized with port 8081 (http) 2025-11-05 15:19:25.891 [main] INFO o.a.catalina.core.StandardService - Starting service [Tomcat] 2025-11-05 15:19:25.891 [main] INFO o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/10.1.16] 2025-11-05 15:19:25.960 [main] INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext 2025-11-05 15:19:25.960 [main] INFO o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 2480 ms 2025-11-05 15:19:25.981 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Found key 'jwt.secret' in PropertySource 'environmentProperties' with value of type String 2025-11-05 15:19:25.982 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Found key 'jwt.expire' in PropertySource 'environmentProperties' with value of type String Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter. Can not find table primary key in Class: "org.world.aquatics.common.domain.SysRoleMenuTbl". 2025-11-05 15:19:26.770 [main] WARN c.b.m.c.injector.DefaultSqlInjector - class org.world.aquatics.common.domain.SysRoleMenuTbl ,Not found @TableId annotation, Cannot use Mybatis-Plus 'xxById' Method. Can not find table primary key in Class: "org.world.aquatics.common.domain.SysUserRoleTbl". 2025-11-05 15:19:26.800 [main] WARN c.b.m.c.injector.DefaultSqlInjector - class org.world.aquatics.common.domain.SysUserRoleTbl ,Not found @TableId annotation, Cannot use Mybatis-Plus 'xxById' Method. Initialization Sequence datacenterId:11 workerId:14 _ _ |_ _ _|_. ___ _ | _ | | |\/|_)(_| | |_\ |_)||_|_\ / | 3.5.5 2025-11-05 15:19:27.193 [main] INFO o.w.a.s.config.ElasticsearchConfig - Elasticsearch 配置加载: host={172.18.56.53}, port={9201} 2025-11-05 15:19:27.520 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Found key 'spring.kafka.bootstrap-servers' in PropertySource 'environmentProperties' with value of type String 2025-11-05 15:19:27.521 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Found key 'spring.kafka.consumer.group-id' in PropertySource 'environmentProperties' with value of type String 2025-11-05 15:19:27.786 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Found key 'springdoc.api-docs.path' in PropertySource 'environmentProperties' with value of type String 2025-11-05 15:19:27.786 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Found key 'springdoc.api-docs.path' in PropertySource 'environmentProperties' with value of type String 2025-11-05 15:19:27.789 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Found key 'springdoc.api-docs.path' in PropertySource 'environmentProperties' with value of type String 2025-11-05 15:19:27.790 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Found key 'springdoc.api-docs.path' in PropertySource 'environmentProperties' with value of type String 2025-11-05 15:19:27.791 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Found key 'springdoc.swagger-ui.path' in PropertySource 'environmentProperties' with value of type String 2025-11-05 15:19:27.791 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Found key 'springdoc.swagger-ui.path' in PropertySource 'environmentProperties' with value of type String 2025-11-05 15:19:27.791 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Found key 'springdoc.api-docs.path' in PropertySource 'environmentProperties' with value of type String 2025-11-05 15:19:27.902 [main] INFO o.s.s.web.DefaultSecurityFilterChain - Will secure any request with [org.springframework.security.web.session.DisableEncodeUrlFilter@476a2819, org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@279ab15e, org.springframework.security.web.context.SecurityContextHolderFilter@3bbc47c9, org.springframework.security.web.header.HeaderWriterFilter@62a81453, org.springframework.web.filter.CorsFilter@571c2ed8, org.springframework.security.web.authentication.logout.LogoutFilter@188ae8d2, org.world.aquatics.web.api.sso.JwtRequestFilter@2055833f, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@144dc2f7, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@403cff1c, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@5810772a, org.springframework.security.web.session.SessionManagementFilter@690677de, org.springframework.security.web.access.ExceptionTranslationFilter@102aa5fc, org.springframework.security.web.access.intercept.AuthorizationFilter@eddc9bb] 2025-11-05 15:19:28.324 [main] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat started on port 8081 (http) with context path '' 2025-11-05 15:19:28.363 [main] INFO o.a.k.c.consumer.ConsumerConfig - ConsumerConfig values: allow.auto.create.topics = true auto.commit.interval.ms = 5000 auto.include.jmx.reporter = true auto.offset.reset = earliest bootstrap.servers = [172.18.56.53:9092] check.crcs = true client.dns.lookup = use_all_dns_ips client.id = consumer-world-aquatics-group-1 client.rack = connections.max.idle.ms = 540000 default.api.timeout.ms = 60000 enable.auto.commit = false exclude.internal.topics = true fetch.max.bytes = 52428800 fetch.max.wait.ms = 500 fetch.min.bytes = 1 group.id = world-aquatics-group group.instance.id = null heartbeat.interval.ms = 3000 interceptor.classes = [] internal.leave.group.on.close = true internal.throw.on.fetch.stable.offset.unsupported = false isolation.level = read_uncommitted key.deserializer = class org.apache.kafka.common.serialization.StringDeserializer max.partition.fetch.bytes = 1048576 max.poll.interval.ms = 300000 max.poll.records = 500 metadata.max.age.ms = 300000 metric.reporters = [] metrics.num.samples = 2 metrics.recording.level = INFO metrics.sample.window.ms = 30000 partition.assignment.strategy = [class org.apache.kafka.clients.consumer.RangeAssignor, class org.apache.kafka.clients.consumer.CooperativeStickyAssignor] receive.buffer.bytes = 65536 reconnect.backoff.max.ms = 1000 reconnect.backoff.ms = 50 request.timeout.ms = 30000 retry.backoff.ms = 100 sasl.client.callback.handler.class = null sasl.jaas.config = null sasl.kerberos.kinit.cmd = /usr/bin/kinit sasl.kerberos.min.time.before.relogin = 60000 sasl.kerberos.service.name = null sasl.kerberos.ticket.renew.jitter = 0.05 sasl.kerberos.ticket.renew.window.factor = 0.8 sasl.login.callback.handler.class = null sasl.login.class = null sasl.login.connect.timeout.ms = null sasl.login.read.timeout.ms = null sasl.login.refresh.buffer.seconds = 300 sasl.login.refresh.min.period.seconds = 60 sasl.login.refresh.window.factor = 0.8 sasl.login.refresh.window.jitter = 0.05 sasl.login.retry.backoff.max.ms = 10000 sasl.login.retry.backoff.ms = 100 sasl.mechanism = GSSAPI sasl.oauthbearer.clock.skew.seconds = 30 sasl.oauthbearer.expected.audience = null sasl.oauthbearer.expected.issuer = null sasl.oauthbearer.jwks.endpoint.refresh.ms = 3600000 sasl.oauthbearer.jwks.endpoint.retry.backoff.max.ms = 10000 sasl.oauthbearer.jwks.endpoint.retry.backoff.ms = 100 sasl.oauthbearer.jwks.endpoint.url = null sasl.oauthbearer.scope.claim.name = scope sasl.oauthbearer.sub.claim.name = sub sasl.oauthbearer.token.endpoint.url = null security.protocol = PLAINTEXT security.providers = null send.buffer.bytes = 131072 session.timeout.ms = 45000 socket.connection.setup.timeout.max.ms = 30000 socket.connection.setup.timeout.ms = 10000 ssl.cipher.suites = null ssl.enabled.protocols = [TLSv1.2, TLSv1.3] ssl.endpoint.identification.algorithm = https ssl.engine.factory.class = null ssl.key.password = null ssl.keymanager.algorithm = SunX509 ssl.keystore.certificate.chain = null ssl.keystore.key = null ssl.keystore.location = null ssl.keystore.password = null ssl.keystore.type = JKS ssl.protocol = TLSv1.3 ssl.provider = null ssl.secure.random.implementation = null ssl.trustmanager.algorithm = PKIX ssl.truststore.certificates = null ssl.truststore.location = null ssl.truststore.password = null ssl.truststore.type = JKS value.deserializer = class org.apache.kafka.common.serialization.StringDeserializer 2025-11-05 15:19:28.445 [main] INFO o.a.kafka.common.utils.AppInfoParser - Kafka version: 3.6.0 2025-11-05 15:19:28.446 [main] INFO o.a.kafka.common.utils.AppInfoParser - Kafka commitId: 60e845626d8a465a 2025-11-05 15:19:28.446 [main] INFO o.a.kafka.common.utils.AppInfoParser - Kafka startTimeMs: 1762327168444 2025-11-05 15:19:28.448 [main] INFO o.s.k.c.DefaultKafkaConsumerFactory$ExtendedKafkaConsumer - [Consumer clientId=consumer-world-aquatics-group-1, groupId=world-aquatics-group] Subscribed to topic(s): world-aquatics-topic 2025-11-05 15:19:28.462 [main] INFO o.w.a.web.api.WebApiApplication - Started WebApiApplication in 5.359 seconds (process running for 7.57) === Config File Loading Information === Active profiles: [] Default profiles: [default] 2025-11-05 15:19:28.464 [main] INFO o.w.a.web.api.WebApiApplication - WebApiApplication启动成功! 2025-11-05 15:19:28.857 [org.springframework.kafka.KafkaListenerEndpointContainer#0-0-C-1] INFO org.apache.kafka.clients.Metadata - [Consumer clientId=consumer-world-aquatics-group-1, groupId=world-aquatics-group] Cluster ID: seNzt9cQRVW5qmRcTDdWIw 2025-11-05 15:19:28.858 [org.springframework.kafka.KafkaListenerEndpointContainer#0-0-C-1] INFO o.a.k.c.c.i.ConsumerCoordinator - [Consumer clientId=consumer-world-aquatics-group-1, groupId=world-aquatics-group] Discovered group coordinator 172.18.56.53:9092 (id: 2147483646 rack: null) 2025-11-05 15:19:28.859 [org.springframework.kafka.KafkaListenerEndpointContainer#0-0-C-1] INFO o.a.k.c.c.i.ConsumerCoordinator - [Consumer clientId=consumer-world-aquatics-group-1, groupId=world-aquatics-group] (Re-)joining group 2025-11-05 15:19:28.872 [org.springframework.kafka.KafkaListenerEndpointContainer#0-0-C-1] INFO o.a.k.c.c.i.ConsumerCoordinator - [Consumer clientId=consumer-world-aquatics-group-1, groupId=world-aquatics-group] Request joining group due to: need to re-join with the given member-id: consumer-world-aquatics-group-1-3cdba838-80cb-4630-9f17-37c5002ee331 2025-11-05 15:19:28.873 [org.springframework.kafka.KafkaListenerEndpointContainer#0-0-C-1] INFO o.a.k.c.c.i.ConsumerCoordinator - [Consumer clientId=consumer-world-aquatics-group-1, groupId=world-aquatics-group] Request joining group due to: rebalance failed due to 'The group member needs to have a valid member id before actually entering a consumer group.' (MemberIdRequiredException) 2025-11-05 15:19:28.873 [org.springframework.kafka.KafkaListenerEndpointContainer#0-0-C-1] INFO o.a.k.c.c.i.ConsumerCoordinator - [Consumer clientId=consumer-world-aquatics-group-1, groupId=world-aquatics-group] (Re-)joining group 2025-11-05 15:19:31.882 [org.springframework.kafka.KafkaListenerEndpointContainer#0-0-C-1] INFO o.a.k.c.c.i.ConsumerCoordinator - [Consumer clientId=consumer-world-aquatics-group-1, groupId=world-aquatics-group] Successfully joined group with generation Generation{generationId=1, memberId='consumer-world-aquatics-group-1-3cdba838-80cb-4630-9f17-37c5002ee331', protocol='range'} 2025-11-05 15:19:31.887 [org.springframework.kafka.KafkaListenerEndpointContainer#0-0-C-1] INFO o.a.k.c.c.i.ConsumerCoordinator - [Consumer clientId=consumer-world-aquatics-group-1, groupId=world-aquatics-group] Finished assignment for group at generation 1: {consumer-world-aquatics-group-1-3cdba838-80cb-4630-9f17-37c5002ee331=Assignment(partitions=[world-aquatics-topic-0])} 2025-11-05 15:19:31.901 [org.springframework.kafka.KafkaListenerEndpointContainer#0-0-C-1] INFO o.a.k.c.c.i.ConsumerCoordinator - [Consumer clientId=consumer-world-aquatics-group-1, groupId=world-aquatics-group] Successfully synced group in generation Generation{generationId=1, memberId='consumer-world-aquatics-group-1-3cdba838-80cb-4630-9f17-37c5002ee331', protocol='range'} 2025-11-05 15:19:31.901 [org.springframework.kafka.KafkaListenerEndpointContainer#0-0-C-1] INFO o.a.k.c.c.i.ConsumerCoordinator - [Consumer clientId=consumer-world-aquatics-group-1, groupId=world-aquatics-group] Notifying assignor about the new Assignment(partitions=[world-aquatics-topic-0]) 2025-11-05 15:19:31.902 [org.springframework.kafka.KafkaListenerEndpointContainer#0-0-C-1] INFO o.a.k.c.c.i.ConsumerCoordinator - [Consumer clientId=consumer-world-aquatics-group-1, groupId=world-aquatics-group] Adding newly assigned partitions: world-aquatics-topic-0 2025-11-05 15:19:31.910 [org.springframework.kafka.KafkaListenerEndpointContainer#0-0-C-1] INFO o.a.k.c.c.i.ConsumerCoordinator - [Consumer clientId=consumer-world-aquatics-group-1, groupId=world-aquatics-group] Found no committed offset for partition world-aquatics-topic-0 2025-11-05 15:19:31.918 [org.springframework.kafka.KafkaListenerEndpointContainer#0-0-C-1] INFO o.a.k.c.c.i.SubscriptionState - [Consumer clientId=consumer-world-aquatics-group-1, groupId=world-aquatics-group] Resetting offset for partition world-aquatics-topic-0 to position FetchPosition{offset=0, offsetEpoch=Optional.empty, currentLeader=LeaderAndEpoch{leader=Optional[172.18.56.53:9092 (id: 1 rack: null)], epoch=0}}. 2025-11-05 15:19:31.919 [org.springframework.kafka.KafkaListenerEndpointContainer#0-0-C-1] INFO o.s.k.l.KafkaMessageListenerContainer - world-aquatics-group: partitions assigned: [world-aquatics-topic-0] 这一段日志输出表明了什么问题?需要怎么去解决这个问题?
11-06
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值