Spring Security i tak filtruje Token

0

Cześć,
mam jakiś kretyński kłopot: otóż chcę aby dwa endpointy /user/register oraz /user/login były dostępne bez sprawdzania JWT..
Tak wygląda mój SecurityConfig:

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
@EnableGlobalMethodSecurity(
        securedEnabled = true,
        jsr250Enabled = true,
        prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    private final CustomUserDetailsService userDetailsService;
    private final AuthenticationHandler authenticationHandler;
    private final AuthenticationFilter jwtAuthenticationFilter;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService)
            .passwordEncoder(passwordEncoder());
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean(BeanIds.AUTHENTICATION_MANAGER)
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .cors()
                .and()
                .csrf().disable()
                .exceptionHandling()
                .authenticationEntryPoint(authenticationHandler)
                .and()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                .antMatchers("/user/register").permitAll()
                .antMatchers("/login").permitAll()
                .anyRequest().authenticated();

        http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
    }

oraz Filter

@Component
public class AuthenticationFilter extends OncePerRequestFilter {
    private static final String AUTHORIZATION_HEADER = "authorization";

    private final JWTTokenManager jwtTokenManager;
    private final CustomUserDetailsService userDetails;

    public AuthenticationFilter (
            final JWTTokenManager jwtTokenManager, final CustomUserDetailsService userDetails
    ) {
        this.jwtTokenManager = jwtTokenManager;
        this.userDetails = userDetails;
    }

    @Override
    protected void doFilterInternal (
            final HttpServletRequest httpServletRequest, final HttpServletResponse httpServletResponse,
            final FilterChain filterChain
    ) throws ServletException, IOException {
        String token = getTokenFromHeaders(httpServletRequest);
        if(jwtTokenManager.verify(token)) {
            UserDetails user = userDetails.loadUserByUUID(jwtTokenManager.getUUID(token));
            UsernamePasswordAuthenticationToken authentication =
                    new UsernamePasswordAuthenticationToken(
                            user, null, user.getAuthorities());
            authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpServletRequest));

            SecurityContextHolder.getContext().setAuthentication(authentication);
        }
        filterChain.doFilter(httpServletRequest, httpServletResponse);
    }

    private String getTokenFromHeaders(HttpServletRequest request) throws ServletException{
        String bearerToken = request.getHeader(AUTHORIZATION_HEADER);
        if (StringUtils.isEmpty(bearerToken) || !bearerToken.startsWith("Bearer "))
            throw new ServletException("Missing or invalid Authorization header");

        return bearerToken.substring(7);
    }
}

no i nadal na endpointach lecą mi 401... Ma ktoś pomysły jak takie proste Security - rejestracja, logowanie, sprawdzanie JWT na endpointach stworzyć albo w Springu, albo i bez niego? Ew. jak rozwiązać ten problem.

0

Leci 500 czyli już masz te endpointy dostępne.
Teraz tylko musisz namierzyć czemu leci 500 - tutaj przydałby się stacktrace towarzyszący tej 500tce i pewnie kod controllera/serwisu do którego strzelasz, bo błąd wcale nie musi być w zamieszczonej przez Ciebie konfiguracji security.

0

Problem został rozwiązany, kłopotem było to, że linia: throw new ServletException("Missing or invalid Authorization header"); zawsze rzucała Exception gdy nie podałem tokenu (nawet przy rejestracji). Gdy złapać to w try catch (zawartość metody doFilterInternal) to możemy to puścić dalej bez zatrzymywania aplikacji i dopuścić Spring'a do tego aby to on sprawdził co robimy z tym endpointem.

Po prostu mój throw zostawał wykonywany zanim Spring wskakiwał ze swoimi sprawdzeniami.

1

Ja nie bardzo rozumiem po co w ogóle masz ten swój filter, przecież to się da ogarnąć na poziomie konfiguracji Spring Security a nie takim lewym filtrem. Spring security ma wsparcie dla JWT natywnie, nie musisz ręcznie tego tokenu parsować i weryfikować...

0

Spróbuj w konstruktorze do filtra dodać AntPathRequestMatcher, bo być może filter jest na wszystkie ścieżki. Albo może coś z CrossOrigin, bez błędu możemy wróżyć z fusów.

Tak poza tym to http://cryto.net/~joepie91/blog/2016/06/13/stop-using-jwt-for-sessions/

0

W jaki sposób można to rozwiązać bez takiego filtra? Byłbym wdzięczny pozbycia się takiego czegoś.

0

Jak rozumiem i tak zamiast JWT do nadzorowania sesji userów lepiej używać Session?

1 użytkowników online, w tym zalogowanych: 0, gości: 1