#java #spring #spring-mvc #spring-security #spring-data-jpa
Вопрос:
Как мне получить адрес электронной почты пользователя в контроллере?
Я пытаюсь получить адрес электронной почты пользователя в контроллере, который пытается войти в систему, но по какой-то причине был заблокирован. Я хочу сообщить пользователю, что пользователь с этим адресом электронной почты был заблокирован. Но для этого мне нужно получить его адрес электронной почты.
Вопрос! Как мне получить адрес электронной почты пользователя в контроллере?
У меня есть SecurityConfig, UserDetail, LoginController.
Здесь я добавил весь проект — https://github.com/romanych2021/mytest сделано специально для этого вопроса
SecurityConfig
package com.mytest.security;
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.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final
UserDetailsService userDetailsService;
public SecurityConfig(UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.mvcMatchers("/login").anonymous()
.mvcMatchers("/user/**").hasRole("USER")
.and()
.csrf().disable()
.formLogin()
.loginPage("/login")
.loginProcessingUrl("/login")
.defaultSuccessUrl("/")
.failureUrl("/login?error=true")
.usernameParameter("email")
.passwordParameter("password")
.and()
.exceptionHandling()
.accessDeniedPage("/403")
.and()
.logout()
.permitAll()
.logoutUrl("/logout")
.logoutSuccessUrl("/")
.invalidateHttpSession(true)
.deleteCookies("JSESSIONID");
}
}
UserDetail
package com.mytest.security;
import com.mytest.model.User;
import com.mytest.service.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@Service
public class UserDetail implements UserDetailsService {
@Autowired
UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
User user = userRepository.findUserByEmail(email);
if (user == null){
throw new UsernameNotFoundException("There is no such user " email);
}
return new org.springframework.security.core.userdetails.User(
user.getEmail(),
user.getPassword(),
user.getEnabled(),
user.getAccount_non_expired(),
user.getCredentials_non_expired(),
user.getAccount_non_locked(),
getAuthorities());
}
private Collection<? extends GrantedAuthority> getAuthorities(){
List<SimpleGrantedAuthority> authList = new ArrayList<>();
authList.add(new SimpleGrantedAuthority("ROLE_USER"));
return authList;
}
}
ЛогинКонтроллер
package com.mytest.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class LoginController {
@GetMapping(value = "/login")
public String loginGet () {
// How do I get the user's email address here?
return "login";
}
}
Ответ №1:
Предполагая, что вы используете предоставленный фильтр проверки подлинности имени пользователя и не выполняли никаких переопределений, и что пользователь уже вошел в вашу систему; вы можете получить доступ к имени пользователя следующим образом:
@GetMapping(value = "/login")
public String loginGet (Authentication auth) {
String username = auth.getName();
return "login";
}
Spring автоматически введет маркер аутентификации по умолчанию, который находится UsernamePasswordAuthenticationToken
здесь.
ИЗМЕНИТЬ: Кажется, я ошибочно принял вопрос за уже вошедший в систему. В случае, если это проблема с ошибкой входа в систему, вы можете сделать следующее:
Шаг 1. Создайте новое исключение проверки подлинности следующим образом:
public class UserBlockedException extends UsernameNotFoundException {
public UserBlockedException(String msg) {
super(msg);
}
}
Шаг 2.Создайте указанное выше исключение в классе UserDetail @Service с сообщением, которое вам нужно показать пользователю, если пользователь заблокирован.
Шаг 3. Покажите сообщение об ошибке в форме входа в систему?ошибка=истина:
<div th:if="${param.error}">
Login Failed. Reason: <span th:text="${session["SPRING_SECURITY_LAST_EXCEPTION"].message"></span>
</div>
Spring Security будет использовать значение по умолчанию SimpleUrlAuthenticationFailureHandler
для обработки вашей ошибки. Это сохранит ваше исключение в качестве атрибута сеанса, доступ к которому вы получите в thymeleaf, как показано на шаге 3.
Комментарии:
1. Вы можете указать адрес электронной почты или имя пользователя как часть сообщения,
UserBlockedException
так как оно было отправленоUserDetail
. Если вам неудобно расширятьUsernameNotFoundException
, чтобы предоставитьUserBlockedException
, вы можете расширитьAuthenticationException
, но тогда проверка должна быть выполнена на заказAuthenticationProvider
. Следуйте этому: baeldung.com/spring-security-authentication-provider
Ответ №2:
public static User getCurrentUser() {
return (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
}
Вам необходимо настроить новый класс пользователя, реализующий учетные записи пользователей, и заставить метод loadUserByUsername службы UserDetailService возвращать экземпляр этого пользователя. Обратитесь к этой статье.
Правка: Я неправильно прочитал исходное сообщение. Пересмотренный ответ jms должен решить вашу проблему.
Комментарии:
1. Я обещаю вам, что это сработает. Это позволит вам вызвать getCurrentUser() в вашем контроллере, получить доступ к полю пользователя и получить его электронную почту. Если вы поделитесь тем, с чем вы боретесь, я могу помочь.
2. @Max Мой ответ был неправильным, я неправильно понял вашу проблему. Вы говорите, что хотите сообщить пользователю, если он был «заблокирован» по какой-либо причине при попытке входа в систему. Заблокирован чем конкретно? Неверное электронное письмо? Отключенная учетная запись?
3. Да, я хочу сообщить ему об этом из этого района. включено, учетная запись неактивна, учетные данные неактивны, учетная запись заблокирована
4. Эти методы вызовут исключение DisabledException, исключение AccountExpiredException, исключение CredentialsExpiredException, исключение LockedException при попытке входа и перенаправления на /вход с параметром «ошибка». Следуйте приведенному ниже редактированию jms и добавьте div с th:if=»${param.error}» и установите текст внутри с помощью th:text=»${сеанс[«SPRING_SECURITY_LAST_EXCEPTION»].сообщение}». Например, если учетная запись пользователя отключена, будет выдано исключение DisabledException, и thymeleaf проанализирует текст как «Пользователь отключен».
Ответ №3:
Насколько я помню, когда вы используете Spring Security, вам не нужен контроллер — фильтр проверки подлинности имени пользователя зарегистрирован в цепочке фильтров безопасности и выполняет проверку подлинности. Так что, я думаю, вы можете проверить это и соответствующим образом скорректировать свою логику. Ссылка
Комментарии:
1. Любой параметр не может быть передан из этого фильтра в контроллер. Я пытался это сделать, но у меня ничего не вышло.