Пользовательский весенний защитный фильтр не вызывается во время выполнения - PullRequest
0 голосов
/ 30 мая 2018

Я пытаюсь включить Spring Security в проекте служб остальной загрузки, и у меня возникают некоторые проблемы.

Я настроил его с этим кодом

@Configuration
@EnableWebSecurity
public class WebSecurity extends WebSecurityConfigurerAdapter {

    @Autowired
    private LdapAuthenticationProvider ldapAuthenticationProvider;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable().authorizeRequests()
            .anyRequest().authenticated()
            .and()
            .httpBasic().and()
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }


    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {

        auth.authenticationProvider(ldapAuthenticationProvider);
    }

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

}

и реализовалпользовательский провайдер аутентификации для входа в LDAP (который имеет нестандартную конфигурацию, поэтому я не смог заставить работать провайдера ldap по умолчанию)

@Component
public class LdapAuthenticationProvider implements AuthenticationProvider {

    @Override
    public Authentication authenticate(Authentication authentication)
            throws AuthenticationException {

        String email = authentication.getName();
        String password = authentication.getCredentials().toString();

        LdapConnection ldap = new LdapConnection();
        String uid = ldap.getUserUID(email);
        if(uid == null || uid == ""){
            throw new BadCredentialsException("User " + email + " not found");
        }

        if(ldap.login(uid, password)){

            return new UsernamePasswordAuthenticationToken(uid, null, new ArrayList<>());
        }else{
            throw new BadCredentialsException("Bad credentials");
        }
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return true;  
        //To indicate that this authenticationprovider can handle the auth request. since there's currently only one way of logging in, always return true

    }

}

Этот код работает нормально, в том смысле, что вызовмои сервисы с базовым заголовком авторизации могут правильно войти в систему и вернуть вызванную услугу.Проблемы начались, когда я попытался вставить другую авторизацию / аутентификацию.Вместо использования базовой аутентификации я хотел бы передать учетные данные из формы в моем интерфейсе реагирования, поэтому я хотел бы передать их как тело json в вызове POST.(идея состоит в том, чтобы сгенерировать токен jwt и использовать его для следующего обмена данными).

Таким образом, я изменил метод настройки следующим образом:

@Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable().authorizeRequests()
            .anyRequest().authenticated()
            .and()
            .addFilter(new JWTAuthenticationFilter(authenticationManager()))
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }

и определил пользовательский фильтр аутентификации:

public class JWTAuthenticationFilter extends
        UsernamePasswordAuthenticationFilter {

    @Autowired
    private AuthenticationManager authenticationManager;

    public JWTAuthenticationFilter(AuthenticationManager authenticationManager) {
        this.authenticationManager = authenticationManager;
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res) throws AuthenticationException{
        String requestBody;
        try{
            requestBody = IOUtils.toString(req.getReader());
            JsonParser jsonParser = JsonParserFactory.getJsonParser();
            Map<String, Object> requestMap = jsonParser.parseMap(requestBody);
            return authenticationManager.authenticate( new UsernamePasswordAuthenticationToken(requestMap.get("email"), requestMap.get("password"), new ArrayList<>()));
        }catch(IOException e){
            throw new InternalAuthenticationServiceException("Something goes wrong parsing the request body",e );
        }
    }

    @Override
    protected void successfulAuthentication(HttpServletRequest req, HttpServletResponse res, FilterChain chain, Authentication auth) throws IOException{

        JwtTokenProvider tokenProvider = new JwtTokenProvider();
        String token = tokenProvider.generateToken(auth.getPrincipal().toString());
        Cookie cookie = new Cookie("jwt",token);
        cookie.setHttpOnly(true);
        cookie.setSecure(true);
        res.addCookie(cookie);

    }

}

Проблема в том, что, что бы я ни делал, среда выполнения вообще не входит в этот фильтр.Чего мне не хватает?Я предполагаю, что это что-то большое и глупое, но я не могу понять это ...

ОБНОВЛЕНИЕ: проблема заключается в том, что UsernamePassWordAuthenticationFilter может быть вызван только через форму.Затем я изменяю свой код для расширения AbstractAuthenticationProcessingFilter.

Измененный фильтр:

public class JWTAuthenticationFilter extends
        AbstractAuthenticationProcessingFilter {


    private AuthenticationManager authenticationManager;

    public JWTAuthenticationFilter(AuthenticationManager authenticationManager) {
        super("/api/secureLogin");
        this.authenticationManager = authenticationManager;
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res) throws AuthenticationException{
        String requestBody;
        try{
            requestBody = IOUtils.toString(req.getReader());
            JsonParser jsonParser = JsonParserFactory.getJsonParser();
            Map<String, Object> requestMap = jsonParser.parseMap(requestBody);
            UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(requestMap.get("email"), requestMap.get("password"), new ArrayList<>()); 
            return authenticationManager.authenticate(token);
        }catch(IOException e){
            throw new InternalAuthenticationServiceException("Something goes wrong parsing the request body",e );
        }
    }
}

и измененный метод настройки:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable().authorizeRequests()
        .antMatchers(HttpMethod.POST, "/api/secureLogin").permitAll()
        .antMatchers(HttpMethod.GET, "/api").permitAll()
        .antMatchers("/api/**").authenticated()
        .and()
        .addFilterBefore(new JWTAuthenticationFilter(authenticationManager()), UsernamePasswordAuthenticationFilter.class)
        .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}

Ответы [ 3 ]

0 голосов
/ 24 августа 2018

Вы ожидаете, что фильтр сработает при доступе к пути api/secureLogin.По умолчанию UsernamePasswordAuthenticationFilter запускается только при доступе к /login.

Если вы добавите следующую строку в конструктор JWTAuthenticationFilter, который расширяет UsernamePasswordAuthenticationFilter, он должен работать:

this.setFilterProcessesUrl("/api/secureLogin");

0 голосов
/ 09 мая 2019

Привет @ Mikyjpeg

Вы можете использовать Имя пользователяPassWordAuthenticationFilter .Его не обязательно вызывать из формы, как вы упомянули.

Пока он вызывается через POST метод с URL /login (вместо вашего api/secureLogin URL), он будет выполнен.

Конструктор использует сопоставление запросов, которое разрешает только этот URL и метод запроса:

public UsernamePasswordAuthenticationFilter() { super(new AntPathRequestMatcher("/login", "POST")); }

0 голосов
/ 30 мая 2018

Я вижу, что вы добавляете конфигурацию при переопределении метода configure, попробуйте добавить сопоставление фильтров в ваш файл web.xml.Примерно так в узле 'web-app':

<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter>
    <filter-name>JWTAuthenticationFilter</filter-name>
    <filter-class>com.yourProject.JWTAuthenticationFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
    <filter-name>JWTAuthenticationFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...