我有一个基于Spring-cloud的微服务应用程序。我在所有这些服务之前也有一个API网关。
我需要支持两种类型的客户端。
其中一个可以使用授权令牌调用我的应用程序(例如通过调用/授权)。令牌基本上是SESSION ID。所有服务器都使用Spring Session Redis共享会话。
第二个客户端只能向我发送http基本身份验证(用户:传递为授权头)。
对于第二个客户端,我需要检查用户是否已经过身份验证并且在redis中有一个活动会话。我在安全配置中的BasicAuthenticationFilter之前添加了过滤器来检查它。
如果用户有一个活动会话,我将SESSIONID放在头部,并从请求中删除授权头(我正在使用自定义的HttpServletRequest包装器)。我的目的是从那时起,Spring将在下游微服务中管理请求,就好像它是用SESSIONID发送的一样。原因是为了避免很长的登录时间(超过1秒)。
这是我的问题:当spring检查SESSIONID是否存在时,它会检查没有任何sessionId的原始请求。
安全配置:
@Resource
@Qualifier("sessions")
private Map<String, String> sessions;
@Autowired
@Qualifier("httpSessionStrategy")
HttpSessionStrategy sessionStrategy;
@Override
protected void configure(HttpSecurity http) throws Exception {
// // @formatter:off
http
.addFilterBefore(setSessionIdInHeader(), BasicAuthenticationFilter.class)
.sessionManagement()
.and()
.exceptionHandling()
.authenticationEntryPoint(restEntryPoint())
.and()
.headers().addHeaderWriter(new StaticHeadersWriter("Server",""))
.and()
.httpBasic()
.authenticationEntryPoint(restEntryPoint())
.and()
.logout().addLogoutHandler(clearTicketOnLogoutHandler())
.logoutSuccessHandler(logoutSuccessHandler())
.and()
.authorizeRequests()
.antMatchers("/index.html", "/login", "/").permitAll()
.antMatchers(HttpMethod.OPTIONS).denyAll()
.antMatchers(HttpMethod.HEAD).denyAll()
.anyRequest().authenticated()
.and()
.authenticationProvider(authenticationProvider)
.csrf()
.disable()
.addFilterAfter(ticketValidationFilter(), SessionManagementFilter.class)
.addFilterAfter(changePasswordFilter(), SessionManagementFilter.class)
.addFilterAfter(httpPolutionFilter(), SessionManagementFilter.class)
.addFilterAfter(saveSessionId(), SessionManagementFilter.class);
// @formatter:on
}
过滤以向请求添加标头:
private Filter setSessionIdInHeader(){
return new OncePerRequestFilter() {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
Jedis jedis = null;
String authorization = request.getHeader("authorization");
String sessionId = null;
if (authorization != null){
if (sessions.get(authorization) != null){ //user already authenticated
sessionId = sessions.get(authorization);
jedis = getJedisPool().getResource();
if (jedis.hgetAll("spring:session:sessions:"+sessionId) != null){ //session alive in redis
log.info("session :"+ sessionId +" exists in redis");
HeaderMapRequestWrapper wrapper = new HeaderMapRequestWrapper(request);
wrapper.addHeader("TOKEN", sessionId);
wrapper.addHeader("mock_authorization", authorization);
filterChain.doFilter(wrapper, response);
}
}
}
filterChain.doFilter(request, response);
}
};
}
更改SESSIONID的标题名称:
@Bean
public HeaderHttpSessionStrategy httpSessionStrategy(){
HeaderHttpSessionStrategy headerHttpSessionStrategy = new HeaderHttpSessionStrategy();
headerHttpSessionStrategy.setHeaderName("TOKEN");
return headerHttpSessionStrategy;
}
private Filter saveSessionId() {
return new OncePerRequestFilter() {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
if(request.getHeader("authorization") != null){
sessions.put(request.getHeader("authorization"), request.getSession().getId());
}else{
sessions.put(request.getHeader("mock_authorization"), request.getSession().getId());
}
}
};
}