Вход в систему безопасности Spring всегда попадает на страницу с ошибкой без сообщения

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

Это мой SecurityConfiguration.java

package com.ffuentese;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    @Autowired
    private DataSource dataSource;

    @Value("${spring.queries.users-query}")
    private String usersQuery;

    @Value("${spring.queries.roles-query}")
    private String rolesQuery;

    @Override
    protected void configure(AuthenticationManagerBuilder auth)
            throws Exception {
        auth.
            jdbcAuthentication()
                .usersByUsernameQuery(usersQuery)
                .authoritiesByUsernameQuery(rolesQuery)
                .dataSource(dataSource)
                .passwordEncoder(bCryptPasswordEncoder);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.
            authorizeRequests()
                .antMatchers("/").permitAll()
                .antMatchers("/login").permitAll()
                .antMatchers("/registration").permitAll()
                .antMatchers("/**").hasAuthority("ADMIN").anyRequest()
                .authenticated().and().csrf().disable().formLogin()
                .loginPage("/login").failureUrl("/login?error=true")
                .defaultSuccessUrl("/home")
                .usernameParameter("email")
                .passwordParameter("password")
                .and().logout()
                .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
                .logoutSuccessUrl("/").and().exceptionHandling()
                .accessDeniedPage("/access-denied");
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web
           .ignoring()
           .antMatchers("/resources/**", "/static/**", "/css/**", "/js/**", "/images/**");
    }

}

Моя форма входа:

<form th:action = "@{/login}" method = "POST" class = "form-signin">
    <h3 class = "form-signin-heading" th:text = "Welcome"></h3>
    <br/>

    <input type = "text" id = "email" name = "email"  th:placeholder = "Email"
        class = "form-control" /> <br/> 
    <input type = "password"  th:placeholder = "Password"
        id = "password" name = "password" class = "form-control" /> <br /> 

    <div align = "center" th:if = "${param.error}">
        <p style = "font-size: 20; color: #FF1C19;">Email or contraseña errónea, por favor intente nuevamente.</p>
    </div>
    <button class = "btn btn-lg btn-primary btn-block" name = "Submit" value = "Login" type = "Submit" th:text = "Login"></button>
</form>

Мой loginController.java

package com.ffuentese;

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

import com.ffuentese.User;

@Controller
public class LoginController {

    @Autowired
    private UserService userService;

    @RequestMapping(value = {"/", "/login"}, method = RequestMethod.GET)
    public ModelAndView login(){
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("login");
        return modelAndView;
    }

    @RequestMapping(value = "/home", method = RequestMethod.GET)
    public ModelAndView homeV(){
        ModelAndView modelAndView = new ModelAndView();
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        modelAndView.setViewName("home");
        return modelAndView;
    }


    @RequestMapping(value = "/registration", method = RequestMethod.GET)
    public ModelAndView registration(){
        ModelAndView modelAndView = new ModelAndView();
        User user = new User();
        modelAndView.addObject("user", user);
        modelAndView.setViewName("registration");
        return modelAndView;
    }

    @RequestMapping(value = "/registration", method = RequestMethod.POST)
    public ModelAndView createNewUser(@Valid User user, BindingResult bindingResult) {
        ModelAndView modelAndView = new ModelAndView();
        User userExists = userService.findUserByEmail(user.getEmail());
        if (userExists != null) {
            bindingResult
                    .rejectValue("email", "error.user",
                            "There is already a user registered with the email provided");
        }
        if (bindingResult.hasErrors()) {
            modelAndView.setViewName("registration");
        } else {
            userService.saveUser(user);
            modelAndView.addObject("successMessage", "User has been registered successfully");
            modelAndView.addObject("user", new User());
            modelAndView.setViewName("registration");

        }
        return modelAndView;
    }

    @RequestMapping(value = "/admin/home", method = RequestMethod.GET)
    public ModelAndView home(){
        ModelAndView modelAndView = new ModelAndView();
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        User user = userService.findUserByEmail(auth.getName());
        modelAndView.addObject("userName", "Welcome " + user.getName() + " " + user.getLastName() + " (" + user.getEmail() + ")");
        modelAndView.addObject("adminMessage","Content Available Only for Users with Admin Role");
        modelAndView.setViewName("admin/home");
        return modelAndView;
    }


}

Таким образом, вместо перехода от входа к / home он попадает в / error. Сама ошибка представляет собой такую ​​строку кода:

{"timestamp":"2018-04-04T21:28:28.944+0000","status":999,"error":"None","message":"No message available"}

Форма действительно работает, потому что, если я перейду из / error и перейду на любой защищенный URL-адрес, они могут быть открыты.

Обновлено: исходный код взят из этого репозитория, и я адаптировал его к своему собственному проекту. https://github.com/gustavoponce7/SpringSecurityLoginTutorial также объяснил здесь

Обновлено: Еще один момент, который я считаю важным, заключается в том, что если я вхожу в систему, а затем снова вхожу в систему, форма, похоже, работает нормально, переводя пользователя из входа в / домой, как и ожидалось. Это странно.

Вы нашли для этого решение?

123 18.04.2018 10:20

Вы справились с этой проблемой?

Damien-Amen 02.08.2018 05:58

Так в чем же выход?

alaster 29.03.2020 15:09

Вот мое решение stackoverflow.com/questions/61029340/…

alaster 04.04.2020 17:27
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
6
4
14 228
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

Ответ принят как подходящий

Может дело в том, нет RequestMapping с ошибкой Param. Возможное решение

@RequestMapping(value = {"/", "/login"}, method = RequestMethod.GET)
    public ModelAndView login(@RequestParam(value = "error", required = false)){
        ModelAndView modelAndView = new ModelAndView();
        if (error != null) {
          modelAndView.setViewName("error page");
        } else modelAndView.setViewName("login");

        return modelAndView;
    }

Редактировать1

Также может быть вызвано отсутствием всех следующих папок в вашем проекте "/static/**", "/js/**", "/css/**", "/img/**", "/json/**", удалите эту конфигурацию или добавьте все папки.

Просто чтобы вы знали, что в моем случае это больше связано с редактированием.

ffuentes 03.08.2018 00:31

Спасибо! Оказывается, web.ignoring().antMatchers() вызовет эту странную ошибку, если вы укажете здесь отсутствующую папку ресурсов или нестатический путь. Проверить stackoverflow.com/a/41147185/1192702

alaster 29.03.2020 20:33

Вы можете добавить параметр always-use-default-target в URL-адрес успеха.

.defaultSuccessUrl("/home",true)

Это означает, что в случае успешного входа вы всегда будете отправлены на /home.

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

Это не идеальное решение, но если вы не хотите переходить на предыдущую страницу после входа в систему, оно поможет предотвратить описанное вами поведение.

Это все равно вызовет ошибку, но теперь пользователи ее не увидят из-за принудительного перенаправления.

alaster 29.03.2020 20:31

Думаю, на вопрос дан ответ, сегодня я столкнулся с этой ошибкой, и у меня была другая ситуация. Я думал, что это поможет некоторым другим новым весенним кодерам, так как мне пришлось некоторое время гуглить.

Необходимо добавить имя атрибута в текстовые поля имени пользователя или пароля. После добавления атрибутов name = "username" и name = "password" в соответствующие типы ввода вы должны иметь возможность войти в систему.

Spring использует параметр name для сопоставления имени пользователя и пароля. так что это обязательно! это может показаться простым, но вот как это работает

создать контроллер и обработать запрос по умолчанию (т.е. получить '/'), если вы впервые используете аутентификацию по умолчанию

Ответ, который подходит и для моего случая, принадлежит 123.

Пригодился и следующий совет от https://www.baeldung.com/spring-security-login:

One reason to override most of the defaults in Spring Security is to hide the fact that the application is secured with Spring Security and minimize the information a potential attacker knows about the application.

Следующее в https://docs.spring.io/spring-security/site/docs/4.2.12.RELEASE/apidocs/org/springframework/security/config/annotation/web/configurers/AbstractAuthenticationFilterConfigurer.html также полезно ссылаться на:

defaultSuccessUrl(String defaultSuccessUrl) Specifies where users will go after authenticating successfully if they have not visited a secured page prior to authenticating.

defaultSuccessUrl(String defaultSuccessUrl, boolean alwaysUse) Specifies where users will go after authenticating successfully if they have not visited a secured page prior to authenticating or alwaysUse is true.

В моем случае это были некоторые другие запросы (один из них был 404 при загрузке ресурса css). После их исправления эта ошибка исчезла.

РЕДАКТИРОВАТЬ

Для правильного решения проблемы необходимо исключить страницу /error из весенних фильтров безопасности. Подробности смотрите в Spring безопасность перенаправляет на страницу с кодом состояния 999.

Другие вопросы по теме