春季安全。如何获取用户电子邮件地址?
Posted
技术标签:
【中文标题】春季安全。如何获取用户电子邮件地址?【英文标题】:Spring Security. How do I get a user email address? 【发布时间】:2021-06-10 03:51:07 【问题描述】:如何在控制器中获取用户电子邮件地址?
我正在尝试获取控制器中尝试登录的用户的电子邮件地址,但由于某种原因被阻止。我想通知用户使用此电子邮件地址的用户已被阻止。但为此,我需要得到他的电子邮件地址。
问题!如何在控制器中获取用户电子邮件地址?
我有 SecurityConfig、UserDetail、LoginController。
在这里我已经添加了整个项目 - https://github.com/romanych2021/mytest 专门为这个问题制作
安全配置
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");
用户详情
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】:假设您使用提供的 UsernamePasswordAuthenticationFilter 并且没有对此进行任何覆盖,并且用户已经登录到您的系统;您可以按如下方式访问用户名:
@GetMapping(value = "/login")
public String loginGet (Authentication auth)
String username = auth.getName();
return "login";
Spring 会自动在此处注入默认的身份验证令牌 UsernamePasswordAuthenticationToken
。
编辑:似乎我把问题误认为已经登录了。如果这是登录失败问题,您可以执行以下操作:
第一步:新建一个AuthenticationException如下:
public class UserBlockedException extends UsernameNotFoundException
public UserBlockedException(String msg)
super(msg);
第 2 步:在 UserDetail @Service 类中抛出上述异常,并在用户被阻止时向用户显示消息。
第 3 步:在 login?error=true 表单中显示错误消息:
<div th:if="$param.error">
Login Failed. Reason: <span th:text="$session["SPRING_SECURITY_LAST_EXCEPTION"].message"></span>
</div>
Spring Security 将使用默认的SimpleUrlAuthenticationFailureHandler
来处理您的错误。它会将您的异常保存为您在 thymeleaf 中访问的会话属性,如步骤 3 所示。
【讨论】:
您可以在UserBlockedException
中包含电子邮件地址或用户名作为消息的一部分,因为它是在UserDetail
中抛出的。如果您不习惯扩展UsernameNotFoundException
以提供UserBlockedException
,您可以扩展AuthenticationException
,但需要在自定义AuthenticationProvider
上进行验证。关注这个:baeldung.com/spring-security-authentication-provider【参考方案2】:
public static User getCurrentUser()
return (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
您需要配置一个实现 UserDetails 的新 User 类,并让 UserDetailService 的 loadUserByUsername 方法返回此 User 的实例。参考这个article。
编辑: 我误读了原帖。 jms 修改后的答案应该可以解决您的问题。
【讨论】:
我向你保证这是可行的。这将允许您在控制器中调用 getCurrentUser()、访问 User 字段并检索他们的电子邮件。如果您分享您遇到的问题,我可以提供帮助。 @Max 我的回答不正确,我误解了你的问题。您说您想通知用户是否由于某种原因尝试登录而被“阻止”。被什么阻止,具体是什么?无效的电子邮件?已停用的帐户? 是的,我想从这方面通知他。启用,accountNonExpired,credentialsNonExpired,accountNonLocked 这些方法在尝试登录时会抛出 DisabledException、AccountExpiredException、CredentialsExpiredException、LockedException,并使用“error”参数重定向到 /login。按照 jms 在下面的编辑并添加一个带有 th:if="$param.error" 的 div 并使用 th:text="$session["SPRING_SECURITY_LAST_EXCEPTION"].message" 设置里面的文本。例如,如果用户的帐户被禁用,则会抛出 DisabledException,并且 thymeleaf 会将文本解析为“用户已禁用”。【参考方案3】:据我所知,当您使用 Spring Security 时,您不需要控制器 - UsernamePasswordAuthenticationFilter 在安全过滤器链中注册并执行身份验证工作。所以我想你可以检查它并相应地调整你的逻辑。 link
【讨论】:
任何参数都不能从这个过滤器传递给控制器。我尝试这样做,但对我来说没有成功。以上是关于春季安全。如何获取用户电子邮件地址?的主要内容,如果未能解决你的问题,请参考以下文章