自定义 WebSecurityConfigurerAdapter

2024-01-06

我在使用 SpringBoot 和 SpringBoot-Security 实现自定义登录身份验证时遇到这个问题。我制造了一个Bitbucket存储库 https://bitbucket.org/dpebadiola/springbootcustomwebsecurity作为该线程的参考(在CustomSecuringWeb 分支 https://bitbucket.org/dpebadiola/springbootcustomwebsecurity/branch/CustomSecuringWeb)。首先,这里的大部分评论都遵循保护 Web 应用程序的安全 https://spring.io/guides/gs/securing-web/教程。

问题是,我很好奇身份验证数据现在如何来自数据库而不仅仅是内存数据(这在生产线应用程序中很常见)。

在整个过程中我做了两次尝试(尽管两次尝试都位于同一个分支上 -我对此不好).

  1. 创建了一个自定义UserDetailsService执行
  2. 创建了一个自定义AbstractUserDetailsAuthentictionProvider执行

我不知道问题出在哪里,但是在检查控制台日志后,两者都返回每个自定义类上的持久性(甚至存储库)DI 为空。

问题是我怎样才能使这两种尝试都发挥作用。以及(可能)这两种尝试中哪一种比另一种更好。


首先,这两种方法用于不同的目的并且不能互换。

Case 1:

UserDetailsService纯粹用作 DAO,通过您的身份验证来定位用户信息,并根据该信息对用户进行身份验证,不应在内部进行任何身份验证UserDetailsService,只是数据访问。 规格清楚地提到了这一点。这就是您正在寻找的。

Case2:

AuthentictionProvider另一方面用于提供自定义的身份验证方法,例如,如果您想在登录名和密码以外的字段上进行自定义身份验证,您可以通过实现来实现AuthentictionProvider并将这个对象提供给您AuthenticationManagerBuilder。我认为这不是您想要在项目中做的事情。您只是希望使用默认方式的登录名和密码根据存储在数据库中的用户来实现身份验证。 在上面Case 1你刚刚实施的地方UserDetailsService,实例AuthentictionProvider是为您创建的AuthenticationManager通过容器,它是DaoAuthenticationProvider因为您提供了 UserDetailsS​​ervice,它只不过是系统中用于检索用户进行身份验证的 DAO。

现在开始实施, 在您的配置中而不是:

  @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//        auth.userDetailsService(new AdminSecurityService());
        auth.authenticationProvider(new AdminSecurityAuthenticationProvider());
    }

做这样的事情

@Autowired
private CustomUserDetailsService userDetailsService;

 @Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(userDetailsService);

}

和你的CustomUserDetailsService必须实施org.springframework.security.core.userdetails.UserDetailsService

@Service
public class CustomUserDetailsService implements UserDetailsService {

    private final AdminRepository userRepository;

    @Autowired
    public CustomUserDetailsService(AdminRepository userRepository) {
        this.userRepository = userRepository;
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        Admin user = userRepository.findByLogin(username);
        if (user == null) {
            throw new UsernameNotFoundException(String.format("User %s does not exist!", username));
        }
        return new UserRepositoryUserDetails(user);
    }

    private final static class UserRepositoryUserDetails extends Admin implements UserDetails {

        private static final long serialVersionUID = 1L;

        private UserRepositoryUserDetails(User user) {
            super(user);
        }

        @Override
        public Collection<? extends GrantedAuthority> getAuthorities() {
            return AuthorityUtils.createAuthorityList("ROLE_USER");
        }

        @Override
        public String getUsername() {
            return getLogin();//inherited from user
        }

        @Override
        public boolean isAccountNonExpired() {
            return true;//not for production just to show concept
        }

        @Override
        public boolean isAccountNonLocked() {
            return true;//not for production just to show concept
        }

        @Override
        public boolean isCredentialsNonExpired() {
            return true;//not for production just to show concept
        }

        @Override
        public boolean isEnabled() {
            return true;//not for production just to show concept
        }
//getPassword() is already implemented in User.class
    }

}

当然,实现取决于您,但您必须能够提供用户密码,以及基于检索到的用户(在您的情况下为 Admin.class )的接口中的其余方法。希望能帮助到你。我没有运行这个例子,所以如果我犯了一些拼写错误,请继续询问是否有东西不起作用。如果您不需要它,我也会从您的项目中删除“AuthentictionProvider”。

在这里你得到了文档:http://docs.spring.io/spring-security/site/docs/4.0.0.RC1/reference/htmlsingle/#tech-userdetailsservice http://docs.spring.io/spring-security/site/docs/4.0.0.RC1/reference/htmlsingle/#tech-userdetailsservice

评论后:您可以设置PasswordEncoder在您的配置方法中,无需太多麻烦即可执行以下操作:

 @Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);

    }
@Bean
    public PasswordEncoder passwordEncoder(){
        PasswordEncoder encoder = new BCryptPasswordEncoder();
        return encoder;
    }

您可以这样做,因为您可以访问AbstractDaoAuthenticationConfigurer从返回auth.userDetailsService(userDetailsService)它允许你配置DaoAuthenticationProvider,这是您选择使用时选择的提供商UserDetailsService。 你是对的PasswordEncoder安顿好了AuthenticationProvider但你不必 实施AuthenticationProvider只需使用从返回的 convinence 对象auth.userDetailsService(userDetailsService)并在该对象上设置编码器,将其传递给AuthenticationPriovider在你的情况下DaoAuthenticationProvider那是已经为你创建的。 就像评论中提到的走鹃一样,您很少需要实现自己的AuthenticationProvider通常大多数身份验证配置调整都可以通过使用来完成AbstractDaoAuthenticationConfigurer如上所述,它是从返回的auth.userDetailsService(userDetailsService).

“如果我想添加密码加密。如果我想进行其他身份验证(例如检查用户是否被锁定、活动、用户是否仍然登录等[不包括密码哈希])将使用身份验证提供者。”

不,这是作为标准身份验证机制的一部分为您完成的http://docs.spring.io/autorepo/docs/spring-security/3.2.0.RELEASE/apidocs/org/springframework/security/core/userdetails/UserDetails.html http://docs.spring.io/autorepo/docs/spring-security/3.2.0.RELEASE/apidocs/org/springframework/security/core/userdetails/UserDetails.html如果你看一下界面UserDetails您将看到,如果上述任何方法返回错误,身份验证都会失败。 实施AuthenticationProvider在非常非标准的情况下确实需要。该框架几乎涵盖了所有标准内容。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

自定义 WebSecurityConfigurerAdapter 的相关文章

随机推荐