使用Spring Boot,Session和Redis创建会话时未复制会话

安德鲁·瑟夫

我正在尝试使用Spring Cloud的Zuul,Eureka和我自己的服务来实现微服务架构。我有多个具有UI和服务的服务,每个服务都可以使用x509安全性对用户进行身份验证。现在,我试图将Zuul放在这些服务的前面。由于Zuul无法将客户端证书转发到后端,所以我认为下一件最好的事情是在Zuul的前门对用户进行身份验证,然后使用Spring Session在后端服务之间复制其身份验证状态。我也跟着教程这里来自Dave Syer和它差不多的作品,但不是第一次请求。这是我的基本设置:

  • 它自己的应用程序中的Zuul代理集可路由到后端服务。已启用Spring安全性以执行x509身份验证。成功验证用户。也有带有@EnableRedisHttpSession的Spring Session
  • 后端服务还启用了Spring Security。我曾尝试在此处启用/禁用x509,但始终要求对特定端点进行身份验证。还使用Spring Session和@EnableRedisHttpSession。

如果您清除了所有会话并重新开始并尝试访问代理,则它将使用zuul服务器的证书将请求发送到后端。然后,后端服务根据该用户证书查找用户,并认为该用户是服务器,而不是在Zuul代理中经过身份验证的用户。如果您只是刷新页面,那么您突然成为后端的正确用户(该用户在Zuul代理中进行了身份验证)。我正在检查的方法是在后端控制器中打印出Principal用户。因此,在第一个请求上,我看到服务器用户,在第二个请求上,我看到真实用户。如果在后端禁用x509,则在第一个请求时,我得到403,然后在刷新时,它允许我进入。

会话似乎没有足够快地复制到后端,因此当在前端对用户进行身份验证时,在Zuul转发请求时它尚未到达后端。

有没有办法保证会话在第一个请求上被复制(即会话创建)?还是我错过了确保其正确运行的步骤?

以下是一些重要的代码段:

Zuul代理:

@SpringBootApplication
@Controller
@EnableAutoConfiguration
@EnableZuulProxy
@EnableRedisHttpSession
public class ZuulEdgeServer {
    public static void main(String[] args) {
        new SpringApplicationBuilder(ZuulEdgeServer.class).web(true).run(args);
    }
}

Zuul配置:

info:
  component: Zuul Server

endpoints:
  restart:
    enabled: true
  shutdown:
    enabled: true
  health:
    sensitive: false

zuul:
  routes:
    service1: /**

logging:
  level:
    ROOT: INFO
#    org.springframework.web: DEBUG
    net.acesinc: DEBUG

security.sessions: ALWAYS
server:
  port: 8443
  ssl:
      key-store: classpath:dev/localhost.jks
      key-store-password: thepassword
      keyStoreType: JKS
      keyAlias: localhost
      clientAuth: want
      trust-store: classpath:dev/localhost.jks

ribbon:
    IsSecure: true

后端服务:

@SpringBootApplication
@EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class, ThymeleafAutoConfiguration.class, org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration.class })
@EnableEurekaClient
@EnableRedisHttpSession
public class Application {

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

后端服务配置:

spring.jmx.default-domain: ${spring.application.name}

server:
  port: 8444
  ssl:
      key-store: classpath:dev/localhost.jks
      key-store-password: thepassword
      keyStoreType: JKS
      keyAlias: localhost
      clientAuth: want
      trust-store: classpath:dev/localhost.jks

#Change the base url of all REST endpoints to be under /rest
spring.data.rest.base-uri: /rest

security.sessions: NEVER

logging:
  level:
    ROOT: INFO
#    org.springframework.web: INFO
#    org.springframework.security: DEBUG
    net.acesinc: DEBUG

eureka:
  instance: 
    nonSecurePortEnabled: false
    securePortEnabled: true
    securePort: ${server.port}
    homePageUrl: https://${eureka.instance.hostname}:${server.port}/
    secureVirtualHostName: ${spring.application.name}

后端控制器之一:

@Controller
public class SecureContent1Controller {
    private static final Logger log = LoggerFactory.getLogger(SecureContent1Controller.class);

    @RequestMapping(value = {"/secure1"}, method = RequestMethod.GET)
    @PreAuthorize("isAuthenticated()")
    public @ResponseBody String getHomepage(ModelMap model, Principal p) {
        log.debug("Secure Content for user [ " + p.getName() + " ]");
        model.addAttribute("pageName", "secure1");
        return "You are: [ " + p.getName() + " ] and here is your secure content: secure1";
    }
}
安德鲁·瑟夫

感谢shobull向我指出了贾斯汀·泰勒对这个问题的回答为了完整起见,我也想在此处提供完整答案。这是一个两部分的解决方案:

  1. 使Spring Session积极提交-自spring-session v1.0起,具有注释属性@EnableRedisHttpSession(redisFlushMode = RedisFlushMode.IMMEDIATE),可将会话数据立即保存到Redis中。文档在这里
  2. 简单的Zuul过滤器,用于将会话添加到当前请求的标头中:

    import com.netflix.zuul.ZuulFilter;
    import com.netflix.zuul.context.RequestContext;
    import javax.servlet.http.HttpSession;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.session.Session;
    import org.springframework.session.SessionRepository;
    import org.springframework.stereotype.Component;
    
    @Component
    public class SessionSavingZuulPreFilter extends ZuulFilter {
        @Autowired
        private SessionRepository repository;
    
        private static final Logger log = LoggerFactory.getLogger(SessionSavingZuulPreFilter.class);
    
        @Override
        public String filterType() {
            return "pre";
        }
    
        @Override
        public int filterOrder() {
            return 1;
        }
    
        @Override
        public boolean shouldFilter() {
            return true;
        }
    
        @Override
        public Object run() {
            RequestContext context = RequestContext.getCurrentContext();
    
            HttpSession httpSession = context.getRequest().getSession();
            Session session = repository.getSession(httpSession.getId());
    
            context.addZuulRequestHeader("Cookie", "SESSION=" + httpSession.getId());
    
            log.trace("ZuulPreFilter session proxy: {}", session.getId());
    
            return null;
        }
    }
    

这两个都应该在您的Zuul代理中。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

使用 Spring Boot 进行 Hazelcast 会话复制

使用.Net Core创建会话时未保存的会话

Spring Boot无法创建会话

如何隔离Spring Boot应用程序Redis和Spring Boot会话全局Redis

从Spring Session Redis获取活动会话计数

Spring Boot启用Redis HTTP会话

使用 spring 创建会话工厂对象时,它显示错误"

Spring Session Redis和Spring Security如何更新用户会话?

在Spring-Session(Redis)和Spring-security中注销用户而不会使会话无效?

Spring Boot安全性:所请求的URL创建了不需要的Redis会话

连接Spring Session和Redis时无法创建springSessionRepositoryFilter

使用Express-Session时,会话数据未保存到内存中

如何使用 Spring Security 在 Spring Boot 中管理会话?

在 Spring Boot 中通过 ActiveMQ Artemis 发送异步消息时如何创建会话工厂?

是否可以在没有Redis的情况下使用Spring Boot会话?

如何在Redis会话中使用Spring Boot身份验证

使用以Redis为后端的Spring会话时,默认会话超时是什么以及如何配置它

Spring Boot 会话管理——PostgreSQL + Redis 组合解决方案

从Android设备使用nusoap Web服务时未创建PHP会话变量

使用 Spring Boot 在 Vaadin 中创建 servlet 以添加会话侦听器

使用 oracle 数据库从 java spring boot 创建会话的最佳方法是什么?

如何使用安全性和会话Spring和RestTemplate为Android创建登录和会话管理

Spring Boot和Spring Data:如何管理Hibernate会话?

ReferenceError:未使用('connect-mongo')(session)定义会话,

使用Spring Boot和嵌入式Tomcat启用会话持久性

无法在spring-boot中使用maximumSessions和maxSessionsPreventsLogin设置并发会话控制

如何使用RedisTemplate访问Spring Redis会话存储的哈希密钥?

未使用PHP Redis会话save_handler

Spring @ResponseBody无法使用会话