春季安全。如何获取用户电子邮件地址?

Posted

技术标签:

【中文标题】春季安全。如何获取用户电子邮件地址?【英文标题】:Spring Security. How do I get a user email address? 【发布时间】:2021-06-10 03:51:07 【问题描述】:

如何在控制器中获取用户电子邮件地址?

我正在尝试获取控制器中尝试登录的用户的电子邮件地址,但由于某种原因被阻止。我想通知用户使用此电子邮件地址的用户已被阻止。但为此,我需要得到他的电子邮件地址。

问题!如何在控制器中获取用户电子邮件地址?

我有 SecurityConfigUserDetailLoginController

在这里我已经添加了整个项目 - 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

【讨论】:

任何参数都不能从这个过滤器传递给控制器​​。我尝试这样做,但对我来说没有成功。

以上是关于春季安全。如何获取用户电子邮件地址?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Facebook API 获取用户的辅助电子邮件地址

如何获取设备用户的电子邮件地址? [复制]

如何通过查询获取用户的电子邮件

如何获取 Android 用户的电子邮件地址?

如何在 Excel 中获取登录用户的电子邮件地址

如何使用他们的电子邮件地址获取用户的详细信息