【问题标题】:How to prevent Redis writes for anonymous user sessions如何防止 Redis 写入匿名用户会话
【发布时间】:2018-01-08 15:22:01
【问题描述】:

我有这个示例应用程序:

package com.example.session;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
public class DemoRedisDataSessionApplication {

    @Configuration
    @EnableWebSecurity
    @EnableRedisHttpSession(redisNamespace = "demo-redis-data-session")
    public static class AppConfiguration extends WebSecurityConfigurerAdapter {

        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.inMemoryAuthentication().withUser("user").password("0000").roles("USER");
        }

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.formLogin().and()
                    .authorizeRequests().antMatchers("/ping").permitAll().and()
                    .authorizeRequests().anyRequest().fullyAuthenticated();
        }

    }

    @RestController
    public static class AppController {
        @GetMapping("/ping")
        public String ping() {
            return "pong";
        }

        @GetMapping("/secured")
        public String secured() {
            return "secured";
        }
    }

    public static void main(String[] args) {
        SpringApplication.run(DemoRedisDataSessionApplication.class, args);
    }

}

当我点击 /secured 时,我得到 302 重定向到 /login 表单,如果我没有登录,这是我所期望的,但是我在 Redis 中得到了一些不需要的条目:

127.0.0.1:6379> keys * 1) "spring:session:demo-redis-data-session:sessions:expires:dbb124b9-c37d-454c-8d67-409f28cb88a6" 2) "spring:session:demo-redis-data-session:expirations:1515426060000" 3) "spring:session:demo-redis-data-session:sessions:dbb124b9-c37d-454c-8d67-409f28cb88a6"

我不想为每个匿名用户(读取爬虫)创建这些数据,那么有没有办法在匿名用户访问安全端点/页面时阻止这些 Redis 条目?

用于此示例项目的其他数据

docker-compose.yml

version: "2" services: redis: image: redis ports: - "6379:6379"

Spring Boot 版本

1.5.9.RELEASE

【问题讨论】:

    标签: spring-boot spring-security spring-session spring-data-redis


    【解决方案1】:

    这不是最佳解决方案,因为它只为所有爬虫创建一个会话,但至少我不会让 Redis 充满不需要的会话。

    import lombok.extern.log4j.Log4j;
    import org.springframework.session.Session;
    import org.springframework.session.SessionRepository;
    import org.springframework.session.web.http.CookieHttpSessionStrategy;
    import org.springframework.session.web.http.MultiHttpSessionStrategy;
    import org.springframework.stereotype.Component;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    @Log4j
    @Component
    public class CrawlerManagerSessionStrategyWrapper implements MultiHttpSessionStrategy {
    
        private CookieHttpSessionStrategy delegate;
        private volatile String crawlerSessionId;
    
        public CrawlerManagerSessionStrategyWrapper() {
            this.delegate = new CookieHttpSessionStrategy();
        }
    
        public String getRequestedSessionId(HttpServletRequest request) {
            String sessionId = getSessionIdForCrawler(request);
            if (sessionId != null)
                return sessionId;
            else {
                return delegate.getRequestedSessionId(request);
            }
        }
    
        public void onNewSession(Session session, HttpServletRequest request, HttpServletResponse response) {
            delegate.onNewSession(session, request, response);
            if (isCrawler(request)) {
                crawlerSessionId = session.getId();
            }
        }
    
        public void onInvalidateSession(HttpServletRequest request, HttpServletResponse response) {
            delegate.onInvalidateSession(request, response);
        }
    
        public HttpServletRequest wrapRequest(HttpServletRequest request, HttpServletResponse response) {
            return request;
        }
    
        public HttpServletResponse wrapResponse(HttpServletRequest request, HttpServletResponse response) {
            return response;
        }
    
        private String getSessionIdForCrawler(HttpServletRequest request) {
            if (isCrawler(request)) {
                SessionRepository<Session> repo = (SessionRepository<Session>) request.getAttribute(SessionRepository.class.getName());
                if (crawlerSessionId != null && repo != null) {
                    Session session = repo.getSession(crawlerSessionId);
                    if (session != null) {
                        return crawlerSessionId;
                    }
                }
            }
            return null;
        }
    
        private boolean isCrawler(HttpServletRequest request) {
            // Here goes the logic to understand if the request comes from a crawler, for example by checking the user agent.
            return true;
        }
    
    }
    

    唯一要实现的是isCrawler 方法来说明请求是否来自爬虫。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-04
      • 1970-01-01
      • 1970-01-01
      • 2013-04-03
      • 2014-10-18
      • 2019-05-22
      相关资源
      最近更新 更多