【问题标题】:can I authenticate a user via a custom method?我可以通过自定义方法对用户进行身份验证吗?
【发布时间】:2015-08-12 23:29:30
【问题描述】:

一个应用程序当前使用 Spring Security,其用户名和密码由 Spring 自动生成的登录表单处理。用户名是有效的电子邮件地址。

我还有其他代码可以向用户发送一封电子邮件,其中包含 url 中的会话 ID 以验证电子邮件地址。这还会向用户发送一条带有自定义密码的短信,以验证他们的电话号码。注册站点、验证电子邮件和验证电话号码的步骤需要几个控制器方法和步骤。

是否有一种快速简便的方法可以将代码添加到现有的控制器方法中,该方法只是将用户声明为已登录?这将使用现有的 spring 安全配置,并通过声明用户来简单地增加已登录。

例如,在控制器方法中:

//confirmed email
//confirmed phone number
//confirmed password
loggedin = true;

澄清:


每次用户登录都需要发送和验证确认文本密码和确认电子邮件。如果无法通过简单的编程语句登录某人,我至少可以用一个简单的程序语句改变用户的角色?因此,他们使用用户名和密码登录到有限的条件状态,并被分配“StepOneRole”。然后他们验证发送给他们的 pin 码并获得“StepTwoRole”。然后他们验证发送给他们的电子邮件链接,并将他们的角色更改为“FullUser”,在其中他们可以实际使用网站的受保护部分。

我试图避免增加不必要的复杂性,但用户需要每次验证 n 个因素。

另外,请注意我的SecurityConfig.java 如下,并使用UserDetailService,在以下答案之一中提到:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;
import org.springframework.security.core.userdetails.UserDetailsService;

@Configuration
@EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired
private UserDetailsService userDetailsService;

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .csrf().disable()
        .formLogin()
            .loginPage("/login")
            .defaultSuccessUrl("/user-home")
            .usernameParameter("j_username")
            .passwordParameter("j_password")
            .loginProcessingUrl("/j_spring_security_check")
            .failureUrl("/login")
            .permitAll()
            .and()
        .logout()
            .logoutUrl("/logout")
            .logoutSuccessUrl("/login")
            .and()
        .authorizeRequests()
            .antMatchers("/user-home").hasAuthority("USER")
            .antMatchers("/j_spring_security_check").permitAll()
            .and()
        .userDetailsService(userDetailsService);

}

}

【问题讨论】:

    标签: java spring spring-mvc spring-security


    【解决方案1】:

    以下代码将以编程方式登录用户:

        Authentication authentication =
            new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authentication);
    

    注意user在它上面的用户对象,实现UserDetails

    同样,要注销用户,可以使用以下代码:

    SecurityContextHolder.getContext().setAuthentication(null);
    

    回复您的评论

    我不确定 Spring 安全性如何在没有您的用户类或某些映射类实现 UserDetails 的情况下使用您的用户和角色。在我的一个项目中,我有一个这样的映射类:

    public class UserDetailsImpl implements UserDetails {
    
    
        private static final long serialVersionUID = 5197941260523577515L;
    
        private User user;
    
        public User getUser() {
            return user;
        }
    
        public void setUser(User user) {
            this.user = user;
        }
    
        public UserDetailsImpl(User user) {
            this.user = user;
        }
    
        @Override
        public Collection<? extends GrantedAuthority> getAuthorities() {
    
            Collection<GrantedAuthority> authorities = new HashSet<GrantedAuthority>(
                    user.getRoles().size() + 1);
    
            for (Role role : user.getRoles())
                authorities.add(new SimpleGrantedAuthority("ROLE_" + role.name()));
    
            authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
    
            return authorities;
    
        }
    
        @Override
        public String getPassword() {
            return user.getPassword();
        }
    
        @Override
        public String getUsername() {
            return user.getEmail();
        }
    
        @Override
        public boolean isAccountNonExpired() {
            return true;
        }
    
        @Override
        public boolean isAccountNonLocked() {
            return true;
        }
    
        @Override
        public boolean isCredentialsNonExpired() {
            return true;
        }
    
        @Override
        public boolean isEnabled() {
            return true;
        }
    
    }
    

    所以,我从我的用户对象创建它的一个实例,并使用它以编程方式登录,如下所示:

    UserDetailsImpl userDetails = new UserDetailsImpl(user);
    
    Authentication authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
    SecurityContextHolder.getContext().setAuthentication(authentication);
    

    回复第三条评论

    是的,User 是一个自编码类。 Here 是指向包含整个项目源代码的 zip 的链接。这是a video tutorial 的逐章来源列表,但您只需查看列表中的最后一个。

    【讨论】:

    • 这是一个Spring Boot应用程序,可以通过“Debug As -> Spring Boot App”运行。如果需要,您可以查看相关的教程。
    • 我想 Debug As -&gt; Java Application 可能在普通的 Eclipse 中工作。 Debug As --&gt; Spring Boot App 会在 STS 中。
    • 是的,根包里有一个。我一直在使用STS,右键项目。
    • 谢谢你和 +1。抱歉,我花了一段时间才解决其他问题,以便我现在可以确认这一点。
    【解决方案2】:

    如果您想要更多参数来进行安全登录,这并不简单,但它还不错。

    Spring 安全性允许您在决定是否记录或返回记录失败状态时决定您想要的任何内容。当您单击电子邮件链接/文本代码等。

    您的登录表单将使用用户/密码组合,但您可以告诉 spring security 也验证该标志对于电话/电子邮件等是否正常或返回失败状态。

    而不是仅仅使用spring security提供的默认用户名/密码/角色认证提供者;您可以修改和覆盖 UserDetailsS​​ervice 和 UserDetails 类,并以您想要的方式实现它们,而不是默认的 spring 安全性。

    例如:我使用自定义 UserDetailsS​​ervice 不仅可以查看我的用户名,还可以验证其状态是否处于活动状态(因此以被禁止或非活动帐户登录将返回 spring 登录错误。

    通过 spring-security.xml(如果通过 .xml 完成,则将弹簧设置放在任何位置)

    <authentication-manager>
        <authentication-provider ref="authProvider"/>
    </authentication-manager>
    <beans:bean id="authProvider" 
        class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
        <beans:property name="userDetailsService" ref="customProvider"/>
    </beans:bean>
    <beans:bean id="customProvider" 
        class="com.asura.projectX.authentication.CustomAuthenticationProvider">
    </beans:bean>
    

    然后您的自定义登录不仅会搜索用户名,还会在尝试登录之前确保电话、电子邮件等正常。示例:

    public class CustomAuthenticationProvider implements UserDetailsService{
    
    @Inject
    private UserService userService; 
    
    @Override
    public UserDetails loadUserByUsername(String username)
            throws UsernameNotFoundException {
        Users user=userService.getUsers(username);
        if(user==null) throw new UsernameNotFoundException("Username not found");
        return user;
    }
    

    }

    userService.getUsers(username) 将是您想要的任何服务/sql。在我的情况下,它会在我的数据库中查找匹配的用户名,如果帐户的状态是活动的或者它返回错误,因此 spring 不会让你登录。如果一切都匹配,登录是自动的(密码太明显了,你甚至可以也可以通过 spring 加密/读取)。

    【讨论】:

    • 谢谢。但是每次用户登录时都需要发送和验证确认文本密码和确认电子邮件。有没有什么方法可以通过简单的程序化花头来改变用户的角色?因此,他们以您描述的方式登录并获得“StepOneRole”。然后他们验证发送给他们的 pin 码并获得“StepTwoRole”。然后他们验证发送给他们的电子邮件链接,他们的角色更改为“FullUser”。
    • 在这种情况下,只在最后一步调用 Spring security.Login form 第一步仅在您登录时显示用户名(电子邮件)(或在该行旁边有一个签入按钮)它取消隐藏/为电子邮件激活码打开下一行,依此类推,一旦所有行都存在,“登录”按钮已启用,该按钮将调用 spring security 调用其登录功能。
    • 如果我在 spring 登录之前确认电子邮件和电话,我怎样才能安全地将电子邮件和电话确认传送到 spring 登录表单?我无法安全地使用 url 参数。右键单击浏览器并查看源代码的人可以查看隐藏的表单字段。如果它是自定义生成并包装在 SSL 中,则其中一些威胁较小。但我不想在传递所有这些信息时制造安全漏洞。
    • 会生成隐藏字段值;只有你可以看到它(保存给别人看你的肩膀/查看源代码;当您单击登录时,该信息将通过表单发布;那里没有安全问题。当您在表单上输入代码时,暴雪游戏的身份验证器的工作方式相同然后发送它以验证您的登录信息;当您有身份验证器时,每次登录时都会这样做。oi60.tinypic.com/fa7j12.jpg
    • 使用 Java 配置而不是 XML 与使用自定义用户详细信息/身份验证有所不同。见stackoverflow.com/questions/25276152/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-03
    • 2015-02-24
    • 1970-01-01
    • 1970-01-01
    • 2013-03-16
    • 2020-09-26
    相关资源
    最近更新 更多