【问题标题】:SpringSecurity UserDetailsService get passwordSpringSecurity UserDetailsS​​ervice 获取密码
【发布时间】:2013-02-03 00:46:45
【问题描述】:

我正在 Spring 中创建身份验证服务。

我正在使用 UserDetailsS​​ervice 获取表单变量,但我发现 loadUserByUsername 只有一个变量 - userName。

如何获取密码?

public class userAuthentication implements UserDetailsService{

    private @Autowired
    ASPWebServicesUtils aspWebServicesUtils;

    @Override
    public UserDetails loadUserByUsername(String name) throws UsernameNotFoundException {

        //how to get password ?

        User user = new User("test", "test", true, true, true, true, getAuthorities(true));

        return user;  

    }

    private List<GrantedAuthority> getAuthorities(boolean isAdmin){

        List<GrantedAuthority> authorityList = new ArrayList<GrantedAuthority>(2);
        authorityList.add(new SimpleGrantedAuthority("USER_ROLE"));
        if(isAdmin){
            authorityList.add(new SimpleGrantedAuthority("ADMIN_ROLE"));
        }
        return authorityList;

    }
//...
}

谢谢

【问题讨论】:

  • 我有提供信息的webserwice,是否存在用户。我必须将登录名和密码传递给这个 webserwice。
  • 您可能应该阅读UserDetailsService 上的FAQdocumentation 以及它的用途。它仅用于将数据加载到框架中。
  • 没有回答你的问题,但只要你有一个带有大量随机参数的构造函数,它就是构建器模式的标志。例如:User.builder().accountExpired(false).accountLocked(false).credentialsExpired(false).roles("ROLE_USER").disabled(false).build();优于 new User(...)

标签: java spring-security


【解决方案1】:

通过request.getParameter("password")UserDetailsService实现中获取密码:

public class MyUserDetailsService implements UserDetailsService {

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String password = request.getParameter("password"); // get from request parameter
        ......
    }
}

RequestContextHolder 基于ThreadLocal

如果您的项目基于 Spring Framework(不是 Spring Boot),请将 RequestContextListener 添加到 web.xml

<listener>
    <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>

【讨论】:

  • spring boot 没有 web.xml
【解决方案2】:

XML 实现:

<authentication-manager  alias="loginAuthenticationManager">
    <authentication-provider ref="loginAuthenticationProvider" />
</authentication-manager>

<!-- Bean implementing AuthenticationProvider of Spring Security -->
<beans:bean id="loginAuthenticationProvider" class="com.config.LoginAuthenticationProvider">
</beans:bean>

身份验证提供者:

public class LoginAuthenticationProvider implements AuthenticationProvider {
    @Override
    public Authentication authenticate(Authentication authentication)
            throws AuthenticationException {
        String name = authentication.getName();
        // You can get the password here
        String password = authentication.getCredentials().toString();

        // Your custom authentication logic here
        if (name.equals("admin") && password.equals("pwd")) {
            List<GrantedAuthority> grantedAuths = new ArrayList<>();
            grantedAuths.add(new SimpleGrantedAuthority("ROLE_USER"));
            return new UsernamePasswordAuthenticationToken(name, password, grantedAuths);
        }
        return null;
    }
    @Override
    public boolean supports(Class<?> authentication) {
        return authentication.equals(UsernamePasswordAuthenticationToken.class);
    }
}

【讨论】:

    【解决方案3】:

    检索用户信息和提供身份验证信息的一些标准(开箱即用)机制包括:

    • inMemoryAuthentication
    • jdbcAuthentication
    • ldapAuthentication
    • userDetailsS​​ervice

    如果以上不适合您的目的,并且您需要自定义解决方案,您可以像这样创建和配置新的身份验证提供程序:

    安全配置:

    @Configuration
    @EnableWebMvcSecurity
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Override
        @Autowired
        public void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.authenticationProvider(new CustomAuthenticationProvider());
        }
    
        ....
    }
    

    身份验证提供者:

    public class CustomAuthenticationProvider implements AuthenticationProvider {
    
        @Override
        public Authentication authenticate(Authentication authentication)
                throws AuthenticationException {
            String name = authentication.getName();
            // You can get the password here
            String password = authentication.getCredentials().toString();
    
            // Your custom authentication logic here
            if (name.equals("admin") && password.equals("pwd")) {
                Authentication auth = new UsernamePasswordAuthenticationToken(name,
                        password);
    
                return auth;
            }
    
            return null;
        }
    
        @Override
        public boolean supports(Class<?> authentication) {
            return authentication.equals(UsernamePasswordAuthenticationToken.class);
        }
    
    }
    

    【讨论】:

    • 我会添加第三个参数到 new UsernamePasswordAuthenticationToken(name, password, new ArrayList())。这样,构造函数会将 isAuthenticated 设置为 true,因此您不会遇到访问受限于经过身份验证的用户的页面的问题
    【解决方案4】:

    如果查看User对象,构造函数中的第二个参数是密码。

    UserDetailsService 用于从后端结构(如数据库)加载用户。当用户尝试使用用户名和密码登录时调用loadUserByUsername 方法,然后由服务负责加载用户定义并将其返回给安全框架。所需的详细信息包括 usernamepasswordaccountNonExpiredcredentialsNonExpiredaccountNonLockedauthorities 等数据。

    一旦 Spring Security 接收到用户对象,它将根据用户输入的密码和其他数据(如用户帐户状态(accountNonExpired、credentialsNonExpired 等))验证用户

    【讨论】:

    • 我知道 - 我正在创造它。我想接收表单中传递的数据。
    • 处理密码是spring框架的职责,安全框架会比较用户输入的密码和服务发送的密码
    • @ArunPJohny,我可以简单地将 UserDetails 密码字段命名为 passwd、pass、password 或任何我想要的,身份验证管理器如何识别它?
    • 将原始密码存储在数据库中是一个非常糟糕的主意。您应该只存储密码的 hash,即使用BCryptPasswordEncoder。不幸的是,这在 UserDetailsS​​ervice 中无法实现,因为它无法访问用户输入的密码。
    【解决方案5】:

    我相信UserDetailsService 应该用于从一些后端存储、数据库、平面文件等获取UserDetails 对象。一旦你拥有了UserDetails,spring security(或你)必须将其与用户提供的用户名(或其他主体)和密码(凭据)进行比较,以验证该用户。

    我认为您没有按照预期的方式使用它。

    【讨论】:

    • 您好,如何在 Spring Security 中针对数据库实施此密码检查?我是否必须重写任何方法或实现任何接口?
    【解决方案6】:

    loadUserByUsername(String name) 是在您的服务实现的接口(我认为是 userServicedetails)上定义的方法。您必须编写实现。

    就像你必须为 getPassword() 或类似的东西编写实现一样...... spring 不提供。我想密码存储在您的用户对象中,但您写道...您是否创建了getPassword() 方法?

    【讨论】:

      猜你喜欢
      • 2011-07-26
      • 2012-07-06
      • 1970-01-01
      • 2016-12-19
      • 2014-10-03
      • 2020-09-30
      • 2012-06-11
      • 1970-01-01
      • 2020-06-01
      相关资源
      最近更新 更多