Spring-boot: применить Servlet Filter ко всем маршрутам, кроме одного - PullRequest
0 голосов
/ 20 ноября 2018

Вопрос для гуру весенней загрузки!

Вариант использования:

Я хочу, чтобы приложение работало по-разному в зависимости от следующих маршрутов:

  • / без аутентификации, без авторизации
  • / render авторизация с помощью веб-токена json (jwt), отправляемого в качестве параметра URL (я знаю, это странно)
  • любые другие маршруты:авторизация с помощью веб-токена json (jwt), отправляемого в качестве параметра URL (я знаю, это странно)

Секрет для jwt хранится как элемент конфигурации приложения (application.yaml) (Я знаю, что это не лучшая практика, это демонстрационное приложение, поэтому мне все равно)

Я использую SpringBoot 2.0.5 и io.jsonwebtoken в качестве библиотеки jwt.

Я реализовал это, используя Servlet Filter, и он работает, но он выглядит ужасно.Я не смог найти способ сказать " Применить этот фильтр сервлетов ко всем конечным точкам, кроме этого списка ".Я прибег к включению логики в метод doFilter, но это кажется действительно уродливым .

Есть ли для этого «наилучшая практика»?

Мой текущий кодвыглядит следующим образом:

SecurityConfiguration

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
    httpSecurity.authorizeRequests()
            .antMatchers("/").permitAll()
            .antMatchers("/render").permitAll()
            .anyRequest().authenticated();
    httpSecurity.headers().frameOptions().disable();
}
}

WebConfigurer

import org.springframework.boot.web.servlet.ServletContextInitializer;
import org.springframework.context.annotation.Configuration;

import javax.servlet.DispatcherType;
import javax.servlet.FilterRegistration;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import java.util.EnumSet;

@Configuration
public class WebConfigurer implements ServletContextInitializer {

@Override
public void onStartup(ServletContext servletContext) throws ServletException {
        EnumSet<DispatcherType> disps = EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.ASYNC);
        initFilter(servletContext, disps);
}

private void initFilter(ServletContext servletContext,
                            EnumSet<DispatcherType> disps) {
FilterRegistration.Dynamic myFilter =
                servletContext.addFilter("myFilter",
                        new JWTAuthenticationFilter());

myFilter.addMappingForUrlPatterns(disps, true, "/app/*");
myFilter.setAsyncSupported(true);
}
}

JWTAuthenticationFilter

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.impl.TextCodec;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.GenericFilterBean;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class JWTAuthenticationFilter extends GenericFilterBean {

    @Value("${security.jwt.token.secret-key}")
    private String secret;

    @Override
    public void doFilter(ServletRequest req,
                         ServletResponse res,
                         FilterChain filterChain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;

        try {
            String path = request.getRequestURI();
            if (!path.equals("/")) {

                String jwsString = request.getParameter("jwt");
                Jws<Claims> jws;

                String base64_encoded_secret = TextCodec.BASE64.encode(secret);

                jws = Jwts.parser()
                        .setSigningKey(base64_encoded_secret)
                        .parseClaimsJws(jwsString);
            }
        } catch (Exception e) {
            System.out.println(e);
            response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authentication failed");
            SecurityContextHolder.clearContext();
        }
        filterChain.doFilter(request, response);
    }
}

1 Ответ

0 голосов
/ 07 декабря 2018

Нашли решение!Я использовал FilterRegistrationBean.Нет способа исключить URL.Мое решение состоит в том, чтобы поместить все приложение в каталог app /, поэтому мне не нужно было помещать фильтр в корень /.

@Bean
public FilterRegistrationBean FilterRegistration() {
    FilterRegistrationBean registration = new  FilterRegistrationBean();
    registration.setFilter(filter);
    registration.setOrder(1);
    registration.addUrlPatterns("/app/*");
    return registration;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...