简体   繁体   中英

Session Validation - Spring Security with Microservices

My current architecture for my web app has a gateway server that orchestrates a bunch of microservices, authorisation occurs at the gateway if a given principle is authenticated they can talk to some downstream services.

The downstream service gets hold of the required data to identify a given authenticated client. However spring securities default behaviour kicks in and throws the expected:

org.springframework.security.access.AccessDeniedException: Access is denied

Given that I can use the session id and + XSRF token in any given Microservice to validate the user is authenticated and know which user is logged in (i'm currently using Http Basic).

My question is there a simpler / declarative approach that could be used in place of having to adding a filter to every Microservice to override spring securities default behaviour? (see my example Pseudo code)

See the attached diagram: Architecture. 在此处输入图片说明

Spring web security config for resource server:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public SessionRepository<ExpiringSession> sessionRepository() {
        return new MapSessionRepository();
    }


    @Bean
    HeaderHttpSessionStrategy sessionStrategy() {
        return new HeaderHttpSessionStrategy();
    }


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors()
              .and().authorizeRequests().anyRequest().authenticated();


        final SessionRepositoryFilter<ExpiringSession> sessionRepositoryFilter = new SessionRepositoryFilter<ExpiringSession>(
                sessionRepository());
        sessionRepositoryFilter
                .setHttpSessionStrategy(new HeaderHttpSessionStrategy());

        http.addFilterBefore(sessionRepositoryFilter,
                ChannelProcessingFilter.class).csrf().disable();
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER);

    }

    public SessionRepository<ExpiringSession> getSessionRepository(){
        return sessionRepository();
    }

}

Header values at the resource microservice:

KEY: cookie VALUE: XSRF-TOKEN=[token_value]; SESSION=[session_value]
KEY: x-requested-with VALUE: XMLHttpRequest
KEY: x-auth-token VALUE: a32302fd-589b-42e1-8b9d-1991a080e904
...

Planned approach (Pseudo code) attach a new filter to the spring securities filter chain that if given flags are true, allow access to secured endpoints.

**
 * A custom filter that can grant access to the current resource
 * if there is a valid XSRF-TOKEN and SESSION present in the shared
 * session cache.
 */
public class CustomAuthenticationFilter extends AnAppropriateFilterChainFilter {

    @Autowired
    SessionRepository sessionRepository;


    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {



        boolean csrfTokenExists = sessionRepository.findByCsrfTokenId(request);

        boolean sessionExists = sessionRepository.findBySessionId(request);

        if (csrfTokenExists && sessionExists) {
            // everything is okay
        } else {
            // invalidate the request as being authenticated
            throw new InsufficientAuthenticationException("Invalid csrf + session pair");

        }

    }


}

After updating my spring boot parent to 2.0.1 Release and changing my spring cloud version to Finchley the issue was resolved by spring boot.

Note session repository and HttpSessionStrategy aren't required,

HttpSessionStrategy is now depreciated since spring session became spring session core.

Using the externalised config for redis and spring boot , all the dependant systems automatically use that cache for validating a valid session providing you have spring security on your class path.

Note if you are using the gateway pattern and Zuul Proxy ensure your proxy routes include the sensitive-headers: property in your app YML / properties, see examples below:

Example auth + gateway using Springboot Configuration of a shared session cache.

Auth Gateway

spring:
  profiles: dev
  redis:
    host: localhost
    port: 6379
  session:
    store-type: redis

server:
  port:   8080

zuul:
  routes:
    # local routes
    api:
      url: forward:/api
      path: /api/**
      sensitive-headers:
    # cloud-resource
    resource:
      url: http://localhost:9002
      path: /resource/**
      strip-prefix: false
      sensitive-headers:

proxy:
  auth:
    routes:
      resource: passthru
      ui: none
      api: passthru

security:
  sessions: ALWAYS

Some Secured Resource Server

spring:
  profiles: dev
  redis:
    host: localhost
    port: 6379
  session:
    store-type: redis
  security:
    enabled: false

server:
  port:  9002

security:
  # Never create a session, but if one exists use it
  sessions: NEVER
  # don't display the auth box
  basic:
    enabled: false

management:
  security:
    enabled: false

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM