Поскольку безопасность - это сложный вопрос, я рекомендую использовать Spring Security , даже если вам поручено обходиться без него. Чтобы проиллюстрировать сложность с безопасностью, я уже могу сказать вам, что ваш текущий код имеет уязвимость , поскольку вы доверяете незашифрованному паролю имени пользователя в качестве единственной аутентификации. Spring Security, с другой стороны, использует ключ для генерации файла cookie, запоминающего меня, поэтому гораздо труднее подделать кого-либо (если вы не знаете ключ).
Итак, если вы будете использовать Spring Security, первое, что вам нужно сделать, это создать UserDetailsService
, который имеет метод с именем loadByUsername()
. Для реализации этого вы можете использовать UserService
и использовать построитель User
для создания пользовательского объекта Spring Security:
public class MyUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
if ("admin".equalsIgnoreCase(username)) {
return User.builder()
.username(username)
// This should contain the hashed password for the requested user
.password("$2a$10$T5viXrOTIkraRe2mZPyZH.MAqKaR6x38L.rbmRp53yQ8R/cFrJkda")
// If you don't need roles, just provide a default one, eg. "USER"
.roles("USER", "ADMIN")
.build();
} else {
// Throw this exception if the user was not found
throw new UsernameNotFoundException("User not found");
}
}
Имейте в виду, что в отличие от вашего исходного UserService.findByUsernameAndPassword()
вы не должны проверять пароль самостоятельно, просто получите объект пользователя и передайте хешированный пароль.
Следующим шагом является предоставление правильного PasswordEncoder
компонента. В моем примере я использую BCrypt с 10 вращениями, поэтому я создал следующий компонент:
@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(10);
}
@Bean
public UserDetailsService userDetailsService() {
return new MyUserDetailsService();
}
}
Следующим шагом является настройка Spring Security. Например:
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/**")
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login.html").permitAll()
.loginProcessingUrl("/login-user").permitAll().usernameParameter("username").passwordParameter("password")
.defaultSuccessUrl("/welcome.html")
.and()
.rememberMe()
.alwaysRemember(true)
.tokenValiditySeconds(30*5)
.rememberMeCookieName("mouni")
.key("somesecret")
.and()
.csrf().disable();
}
В этом случае все конечные точки (/**
) будут защищены, у вас будет форма входа в систему login.html
, содержащая два поля формы (username
и password
). Назначение формы должно быть /login-user
, и когда пользователь успешно вошел в систему, он будет перенаправлен на /welcome.html
.
Подобно тому, что вы написали в своем коде, это сгенерирует файл cookie с именем mouni
, содержащий значение (больше не простое имя пользователя), и будет действовать в течение 150 секунд, как в вашем примере.
Я отключаю CSRF здесь, потому что я использую простую форму HTML, в противном случае мне пришлось бы добавить шаблонизатор для передачи ключа CSRF. В идеале вы должны оставить это включенным.