Защита Spring включена и больше не обслуживает страницу входа по умолчанию и не обрабатывает запросы, сделанные на «myserver/вход».

#java #spring #spring-security #jwt

Вопрос:

Я работал над демонстрацией Spring Security и одновременно пытался добавить учетные данные для входа в мое существующее приложение. Все шло нормально, пока не появился более длинный раздел, в котором демо-версия заставила меня создать пользовательский фильтр аутентификации, и при загрузке страница входа в систему исчезла и возвращала 404 из отправленных запросов myserver/login . С момента последней работы я создал следующую конфигурацию безопасности:

 @Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    private final UserDetailsService userDetailsService;
    private final BCryptPasswordEncoder bCryptPasswordEncoder;

    @Autowired
    public SecurityConfig(UserDetailsService userDetailsService, BCryptPasswordEncoder bCryptPasswordEncoder) {
        this.userDetailsService = userDetailsService;
        this.bCryptPasswordEncoder = bCryptPasswordEncoder;
    }

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

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable()
                .authorizeRequests().anyRequest().permitAll()
                .and()
                .sessionManagement().sessionCreationPolicy(STATELESS)
                .and()
                .formLogin().loginPage("/login")
                .and()
                .addFilter(new CustomAuthenticationFilter(authenticationManagerBean()));
    }

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

Я прочитал кучу вопросов и подумал, что что-то происходит с пользовательским фильтром аутентификации, и я не указал страницу входа в систему, и с тех пор я изменил эту конфигурацию на:

     protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable()
                .authorizeRequests().anyRequest().permitAll()
                .and()
                .sessionManagement().sessionCreationPolicy(STATELESS)
                .and()
                .formLogin().loginPage("/login")
                .and()
                .addFilter(new CustomAuthenticationFilter(authenticationManagerBean()));
    }
 

При отладке я вижу, что выполняется конфигурация http. На данный момент ничто в пользовательском фильтре аутентификации не доступно за пределами конструктора, но в случае, если это имеет значение, код фильтра выглядит следующим образом:

 public class CustomAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
    private final AuthenticationManager authenticationManager;

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

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        UsernamePasswordAuthenticationToken authenticationToken =
                new UsernamePasswordAuthenticationToken(username,
                password);
        return authenticationManager.authenticate(authenticationToken);
    }

    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response,
                                            FilterChain chain, Authentication authentication)
            throws IOException, ServletException {
        User user = (User) authentication.getPrincipal();
        String access_token = createToken(user, request, response, 10);
        String refresh_token = createToken(user, request, response, 60);
        Map<String, String> tokens = createTokenMap(access_token, refresh_token);
        response.setContentType(APPLICATION_JSON_VALUE);
        new ObjectMapper().writeValue(response.getOutputStream(), tokens);
    }

    private String createToken(User user, HttpServletRequest request, HttpServletResponse response, int minutes) {
        //Poor practice acknowledged... only exposed for this demo application
        Algorithm algorithm = Algorithm.HMAC256("secret".getBytes());
        return JWT.create()
                .withSubject(user.getUsername())
                .withExpiresAt(new Date(System.currentTimeMillis()   (minutes * 60 * 1000)))
                .withIssuer(request.getRequestURL().toString())
                .withClaim("roles",
                        user.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList()))
                .sign(algorithm);
    }

    private Map<String, String> createTokenMap(String access_token, String refresh_token) {
        Map<String, String> tokens = new HashMap<>();
        tokens.put("access_token", access_token);
        tokens.put("refresh_token", refresh_token);
        return tokens;
    }
}
 

У меня есть следующие зависимости для безопасности/интернета в моей сборке gradle:

     implementation 'org.springframework.boot:spring-boot-starter-web'

    implementation group: 'org.springframework.security', name: 'spring-security-config', version: '5.3.0.RELEASE'
    implementation group: 'com.auth0', name: 'java-jwt', version: '3.18.1'

    implementation 'org.springframework.boot:spring-boot-starter-security'
    implementation 'org.springframework.security:spring-security-test'
    implementation 'org.springframework.boot:spring-boot-starter-validation'
 

Поскольку я запустил этот учебник, интегрировав его с моим существующим приложением, которое использует интерфейс React, я думаю, что конфликт может возникнуть из-за уже существующей маршрутизации, но для меня это не имеет особого смысла, так как страница входа обслуживалась до тех пор, пока я не внедрил пользовательский фильтр аутентификации.

На данный момент я попытался вернуть кучу кода, чтобы попытаться вернуться к тому моменту, когда у меня есть страница входа в систему, но ничего не сработало. Есть ли что-нибудь, что я могу добавить, чтобы вернуть функциональность spring по умолчанию myserver/login ? Я бы очень хотел поиграть с запросами на токены/и т. Д. И, В конечном счете, изучить базовую регистрацию для этого приложения.

Дайте мне знать, если может потребоваться какой-либо другой код. Спасибо!

Комментарии:

1. Трудно сделать предложение. Можете ли вы попробовать добавить «.PermitAll()» после «.formLogin().Страница входа («/вход»)»? Так и будет «.formLogin().Страница входа(«/вход»).PermitAll()»

2. При использовании loginPage dsl вы сообщаете Spring Security, что у вас есть пользовательская страница входа. Если вы хотите использовать страницу входа по умолчанию, вы можете опустить loginPage , например: .formLogin().and()...

3. К сожалению, ни то, ни другое не имело значения. Приложение по-прежнему не защищено логином. Кроме того, когда я начал с Spring Security, он дал мне пароль по умолчанию, и он больше этого не делает. Хотя в аннотации конфигурации есть Spring, выполняемая через конфигурацию http, создается впечатление, что безопасность полностью отключена.

4. Вы указываете authorizeRequests().anyRequest().permitAll() , что означает, что все запросы разрешены без аутентификации. Может быть, вам стоит попробовать использовать authorizeRequests().anyRequest().authenticated().and().formLogin().loginPage("/login").permitAll()

5. прежде всего, вы устанавливаете .formLogin().loginPage("/login") , что означает, что spring boot ожидает, что вы предоставите страницу входа в систему в этом месте. Вы там что-нибудь подаете? Во-вторых, не могли бы вы также предоставить свои журналы отладки. В-третьих, передача имени пользователя и пароля в качестве параметров запроса чрезвычайно опасна, кроме того, фильтры обычно не используются в качестве точки входа в систему. фильтры используются для проверки людей, которые предоставляют токены или файлы cookie сеанса.

Ответ №1:

Переходим authorizeRequests().anyRequest().permitAll() на authorizeRequests().anyRequest().authenticated().and().formLogin().permitAll() страницу входа в систему! Я опустил указание страницы, поскольку у меня еще нет пользовательской, но эта конфигурация привела меня к тому, что я могу использовать учетные данные для входа, что было моим первоначальным вопросом, поэтому я публикую это как ответ. Последующий вопрос в комментариях.