Spring webflux custom authentication for API

前端 未结 4 1207
囚心锁ツ
囚心锁ツ 2020-12-07 23:07

I am creating an API for an Angular 5 application. I would like to use JWT for authentication.
I would like to use the features that are provided by spring security so I

4条回答
  •  無奈伤痛
    2020-12-07 23:48

    For those that have same issue(Webflux + Custom Authentication + JWT) I solved using AuthenticationWebFilter, custom ServerAuthenticationConverter and ReactiveAuthenticationManager, following the code hope could help someone in the future. Tested with latest version(spring-boot 2.2.4.RELEASE).

    @EnableWebFluxSecurity
    @EnableReactiveMethodSecurity
    public class SpringSecurityConfiguration {
        @Bean
        public SecurityWebFilterChain configure(ServerHttpSecurity http) {
        return http
            .csrf()
                .disable()
                .headers()
                .frameOptions().disable()
                .cache().disable()
            .and()
                .authorizeExchange()
                .pathMatchers(AUTH_WHITELIST).permitAll()
                .anyExchange().authenticated()
            .and()
                .addFilterAt(authenticationWebFilter(), SecurityWebFiltersOrder.AUTHENTICATION)
                .httpBasic().disable()
                .formLogin().disable()
                .logout().disable()
                .build();
        }
    

    @Autowired private lateinit var userDetailsService: ReactiveUserDetailsService

    class CustomReactiveAuthenticationManager(userDetailsService: ReactiveUserDetailsService?) : UserDetailsRepositoryReactiveAuthenticationManager(userDetailsService) {
    
        override fun authenticate(authentication: Authentication): Mono {
            return if (authentication.isAuthenticated) {
                Mono.just(authentication)
            } else super.authenticate(authentication)
        }
    }
    
    private fun responseError() : ServerAuthenticationFailureHandler{
        return ServerAuthenticationFailureHandler{ webFilterExchange: WebFilterExchange, _: AuthenticationException ->
            webFilterExchange.exchange.response.statusCode = HttpStatus.UNAUTHORIZED
            webFilterExchange.exchange.response.headers.addIfAbsent(HttpHeaders.LOCATION,"/")
            webFilterExchange.exchange.response.setComplete();
        }
    }
    
        private AuthenticationWebFilter authenticationWebFilter() {
            AuthenticationWebFilter authenticationWebFilter = new AuthenticationWebFilter(reactiveAuthenticationManager());
            authenticationWebFilter.setServerAuthenticationConverter(new JwtAuthenticationConverter(tokenProvider));
            NegatedServerWebExchangeMatcher negateWhiteList = new NegatedServerWebExchangeMatcher(ServerWebExchangeMatchers.pathMatchers(AUTH_WHITELIST));
            authenticationWebFilter.setRequiresAuthenticationMatcher(negateWhiteList);
            authenticationWebFilter.setSecurityContextRepository(new WebSessionServerSecurityContextRepository());
            authenticationWebFilter.setAuthenticationFailureHandler(responseError());
            return authenticationWebFilter;
        }
    }
    
    
    public class JwtAuthenticationConverter implements ServerAuthenticationConverter {
        private final TokenProvider tokenProvider;
    
        public JwtAuthenticationConverter(TokenProvider tokenProvider) {
        this.tokenProvider = tokenProvider;
        }
    
        private Mono resolveToken(ServerWebExchange exchange) {
        log.debug("servletPath: {}", exchange.getRequest().getPath());
        return Mono.justOrEmpty(exchange.getRequest().getHeaders().getFirst(HttpHeaders.AUTHORIZATION))
                .filter(t -> t.startsWith("Bearer "))
                .map(t -> t.substring(7));
        }
    
        @Override
        public Mono convert(ServerWebExchange exchange) {
        return resolveToken(exchange)
                .filter(tokenProvider::validateToken)
                .map(tokenProvider::getAuthentication);
        }
    
    }
    
    
    public class CustomReactiveAuthenticationManager extends UserDetailsRepositoryReactiveAuthenticationManager {
        public CustomReactiveAuthenticationManager(ReactiveUserDetailsService userDetailsService) {
        super(userDetailsService);
        }
    
        @Override
        public Mono authenticate(Authentication authentication) {
        if (authentication.isAuthenticated()) {
            return Mono.just(authentication);
        }
        return super.authenticate(authentication);
        }
    }
    

    PS: The TokenProvider class you find at https://github.com/jhipster/jhipster-registry/blob/master/src/main/java/io/github/jhipster/registry/security/jwt/TokenProvider.java

提交回复
热议问题