Внедрение входа в систему вручную с помощью Spring Security

Я разрабатываю приложение с Spring Boot. Теперь я хочу реализовать контроль учетных записей, и я представляю Spring Session и Spring Security. Это внутреннее приложение, основанное на службах REST, интерфейсная часть будет отдельным приложением, использующим эти службы. Я хочу контролировать, чтобы каждый пользователь, обращающийся к ресурсам, входил в систему.

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

Мой контроллер:

@RestController
@RequestMapping("/customer")
public class CustomerController {

    @Autowired
    private AuthenticationService authenticationService;

    @PostMapping("/login")
    public ResponseEntity loginSubmit(@RequestBody LoginForm form) {
        Errors errors = authenticationService.validateLoginForm(form);
        if (!errors.hasErrors()) {
            CustomerDTO result = authenticationService.findCustomerByEmailAndPassword(form);
            return new ResponseEntity(result, HttpStatus.OK);
        } else {
            return new ResponseEntity(errors.getAllErrors(), HttpStatus.OK);
        }
    }

    @GetMapping("/login")
    public ResponseEntity testBrowser() {
        return new ResponseEntity("Hello world", HttpStatus.OK);
    }

    [ . . . Other services . . . ]
}

Конфигурация безопасности Spring:

@EnableWebSecurity
@Configuration
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                    .anyRequest().authenticated()
                    .and()
                .formLogin()
                    .loginPage("/customer/login")
                    .permitAll()
                    .and()
                .logout()
                    .permitAll()
                    .and()
                .httpBasic();
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/h2-console/**");
    }

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

}

По сути, это ограничивает доступ всех незарегистрированных пользователей к любой службе, кроме входа в систему. В моем контроллере реализовано два метода входа в систему. Один — GET для целей тестирования, другой — POST. Когда я обращаюсь к браузеру (GET), он работает, и я могу попасть в точку останова. Однако, когда я пробую POST (через Postman), он возвращает 401 Unauthorized, как и остальные службы, требующие входа в систему. Точка останова никогда не срабатывает.

Я верю, что следую шаблону. Что мне не хватает, пожалуйста?


person bohemian    schedule 19.12.2018    source источник
comment
Если вы не хотите использовать методологию входа Spring, почему вы вызываете .formLogin()?   -  person aBnormaLz    schedule 19.12.2018
comment
Я делаю это, чтобы иметь обработчик входа в систему и исключить его из ограниченных методов. Если вы считаете, что это не так, пожалуйста, не стесняйтесь отвечать на вопрос. Я спрашиваю, как именно это должно быть сделано.   -  person bohemian    schedule 19.12.2018
comment
Просто не делайте этого, так как это создает больше проблем, чем решает, вы теряете большую часть встроенных функций, которые вам пришлось бы вручную интегрировать в свой контроллер. Если вы не хотите использовать обычный логин Spring Security, это нормально, но затем создайте еще один фильтр для использования в цепочке фильтров, чтобы вы интегрировались со всеми материалами Spring Security вместо того, чтобы пытаться собрать их вместе в контроллере.   -  person M. Deinum    schedule 19.12.2018
comment
Как указано, создайте фильтр и интегрируйте его в цепочку безопасности. Также что не так с обычным фильтром Spring Security? Почему бы просто не использовать это, по-видимому, вы все равно передаете имя пользователя и пароль (в теле как JSON/XML или что-то еще) и проверяете это. Spring Security делает именно это. Глядя на то, что у вас есть единственная разница в том, что вы используете JSON/XML для передачи вместо обычной формы.   -  person M. Deinum    schedule 19.12.2018
comment
@ М.Дейнум, спасибо. Я пытаюсь выяснить, что лучше всего, и следует ли мне поручить безопасность сделать все или настроить ее. Кроме того, что вы подразумеваете под фильтром? Это то же самое, что и валидатор?   -  person bohemian    schedule 20.12.2018
comment
Если вы не доверяете Spring Security, то зачем его использовать? Кроме того, почему бы вам не довериться хорошо протестированной и широко используемой библиотеке безопасности, которая сделает все это за вас?   -  person M. Deinum    schedule 20.12.2018
comment
@M.Deinum Я никогда не говорил, что не доверяю этому, мне было интересно, доверить вариант использования Spring или перехватить контроль над ним. Тем не менее, ваша позиция по этому вопросу ясна, спасибо за отзыв.   -  person bohemian    schedule 20.12.2018
comment
Аутентификация является частью всей системы безопасности. Вы можете сделать это самостоятельно, однако вам также потребуется вручную интегрироваться с Spring Security, чтобы часть авторизации работала с Spring Security. Поскольку Spring Security поддерживает оба варианта и позволяет довольно легко интегрировать собственный фильтр аутентификации в цепочку, я бы предложил использовать его.   -  person M. Deinum    schedule 21.12.2018


Ответы (1)


В весенних документах по безопасности упоминаются два параметра:

  1. страница авторизации
  2. URL-адрес обработки входа

Во-первых, пользователь будет перенаправлен с помощью GET в случае, если он не войдет в систему, а во-вторых, форма страницы входа будет отправлена ​​​​с помощью POST.

Вы получаете 401 Unauthorized, потому что значением по умолчанию для login-processing-url является /login, а не /customer/login

документы: https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/

person Maxim Markov    schedule 19.12.2018
comment
Это похоже на правильный ответ, но я все еще сталкиваюсь с той же проблемой. Я пробовал .formLogin().loginPage(/customer/login).loginProcessingUrl(/customer/login).permitAll(), а также пытался дать им разные имена конечных точек @MaximMarkov, но все равно тот же результат 401. - person bohemian; 19.12.2018
comment
@bohemian Пожалуйста, опубликуйте свой полный класс, который расширяет WebSecurityConfigurerAdapter, чтобы у нас была лучшая картина. - person Ian Lim; 20.12.2018
comment
@IanLim весь класс указан выше в вопросе, единственное изменение состоит в том, что там, где было сказано .loginPage(, теперь написано .loginProcessingUrl(. Все тот же эффект: 401, метод не срабатывает. Я получаю тот же результат, когда включаю loginPage и loginProcessingUrl. - person bohemian; 20.12.2018
comment
Как уже заметил М. Дениум, вы вообще что-то делаете не так. Платформа безопасности Spring предоставляет множество способов ее настройки и расширения, но вы решили заменить основную часть ее функциональности. Стандартный способ аутентификации пользователя — настроить URL-адрес обработки входа, который затем обрабатывается UsernamePasswordAuthenticationFilter. Вы можете передать его с помощью своего пользовательского источника пользователей, внедрив интерфейс UserDeatailsService и зарегистрировав его как bean-компонент. - person Maxim Markov; 27.12.2018