Spring Zuul API Gateway with Spring Session / Redis Authenticate and Route in same Request

Justin Taylor picture Justin Taylor · Jan 12, 2016 · Viewed 9.7k times · Source

I have been really been searching high and low for the last few days on how to do this and have finally decided to admit defeat and ask for help, please!!!

I have followed Dr Dave Syer's tutorial on Angular and Spring Security specifically the Zuul Proxy as an api gateway and using Spring Session with Redis (https://github.com/spring-guides/tut-spring-security-and-angular-js/tree/master/double#_sso_with_oauth2_angular_js_and_spring_security_part_v)

The issue I am having is that I am calling resource rest services via the gateway from an external application with the following header:

String plainCreds = "user:password";
byte[] plainCredsBytes = plainCreds.getBytes();
byte[] base64CredsBytes = Base64.getEncoder().encode(plainCredsBytes);
String base64Creds = new String(base64CredsBytes);

HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic " + base64Creds);

to be authenticated and then routed by zuul and then the resource to have access to the authenticated session via redis.

The issue is that the session seems to only commit to redis in the gateway after the request has responded. So what is happening is that when I call a resource service with the header, I can see the successful authentication occurring in the gateway and session being created, however I am getting a 403 in the resource due to the session not being in redis after its been routed via zuul.

However if I get the error, grab the session id and add it to the header and try again it works because now my authenticated session is available for the resource project after its been routed.

Please could someone point me in the direction of how I go about getting my calls via the gateway to authenticate and route in the same request please?

Thanks Justin

Answer

shobull picture shobull · Aug 10, 2016

I followed Justin Taylor's posts on different pages so this is his solution. It makes me sense to have solution with source code here:

  1. Make Spring Session commit eagerly - since spring-session v1.0 there is annotation property @EnableRedisHttpSession(redisFlushMode = RedisFlushMode.IMMEDIATE) which saves session data into Redis immediately. Documentation here.
  2. Simple Zuul filter for adding session into current request's header:
@Component
public class SessionSavingZuulPreFilter extends ZuulFilter {

    @Autowired
    private SessionRepository repository;

    @Override
    public String filterType() {
        return "pre";
    }

    @Override
    public int filterOrder() {
        return 0;
    }

    @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.info("ZuulPreFilter session proxy: {}", session.getId());

        return null;
    }

}

Once more - this is not my solution - credentials go to Justin Taylor.