使用没有 LoadTimeWeaving 的服务自定义 UserDetails

Customizing UserDetails using a service without LoadTimeWeaving

我需要使用对象列表进行访问控制。获取该列表的查询非常复杂且冗长,因此我想在用户向服务器进行身份验证时将其缓存在用户对象中。 我决定尝试通过自定义实现 UserDetailService 和这个 WebSecurityConfig:

来解决这个问题
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

...


        @Override
        public void init(AuthenticationManagerBuilder auth) throws Exception {
            String ldapURI = "ldap://" + ldaHost + ":" + ldapPort + "/" + ldapBasis;

            DefaultSpringSecurityContextSource contextSource = new DefaultSpringSecurityContextSource(ldapURI);
            contextSource.setUserDn(ldapUser);
            contextSource.setPassword(ldapPassword);
            contextSource.afterPropertiesSet();

            LdapAuthenticationProviderConfigurer<AuthenticationManagerBuilder> ldapAuthenticationProviderConfigurer = auth
                    .ldapAuthentication().userDetailsContextMapper(new LdapUserDetailsContextMapper());

            ldapAuthenticationProviderConfigurer
                    .userSearchFilter("(&(criteria={0}))")
                    .userSearchBase("ou=usersearchbase").contextSource(contextSource);
        }
}

用数据填充用户对象的 ContextMapper:

public class LdapUserDetailsContextMapper implements UserDetailsContextMapper {

private final org.slf4j.Logger log = LoggerFactory.getLogger(this.getClass());

private DataService dataService;

public UserDetails mapUserFromContext(DirContextOperations ctx, String username,
                                      Collection<? extends GrantedAuthority> authorities) {

    AppUser user = new AppUser();
    user.setUsername(ctx.getStringAttribute("uid"));
    user.setName(ctx.getStringAttribute("cn"));
    user.setSurname(ctx.getStringAttribute("sn"));
    user.setMail(ctx.getStringAttribute("mail"));
    user.setRoleUser();    

user.setManaged(dataService.getManagedData(user.getMail()));

                    return user;
                }

问题是我没有办法将我的 DataService 注入到这个进程中——ContextMapper 和 @Configure class 都不是托管 bean,这使得 @Autowired 不可能。我想避免使用 LoadTimeWeaving,因为使用它会使部署变得非常困难 - 我还有其他选择吗?

我发现了这两个类似的问题:Why is my Spring @Autowired field null?在控制器class中有同样的问题,它可以变成托管bean;其他两个提到的解决方案对我都不起作用(dataService 始终为空)和 再次推荐LoadTimeWeaving。

我还发现明显的解决方案提到在 init 方法中使用 @Autowired,但我也无法让它工作(尝试使用注入的数据服务调用 ContextMapper 构造函数)

只需将其设为 spring 托管 bean。

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

...


        @Override
        public void init(AuthenticationManagerBuilder auth) throws Exception {
            String ldapURI = "ldap://" + ldaHost + ":" + ldapPort + "/" + ldapBasis;

            DefaultSpringSecurityContextSource contextSource = new DefaultSpringSecurityContextSource(ldapURI);
            contextSource.setUserDn(ldapUser);
            contextSource.setPassword(ldapPassword);
            contextSource.afterPropertiesSet();

            LdapAuthenticationProviderConfigurer<AuthenticationManagerBuilder> ldapAuthenticationProviderConfigurer = auth
                    .ldapAuthentication().userDetailsContextMapper(userDetailsContextMapper());

            ldapAuthenticationProviderConfigurer
                    .userSearchFilter("(&(criteria={0}))")
                    .userSearchBase("ou=usersearchbase").contextSource(contextSource);
        }
    @Bean
    public LdapUserDetailsContextMapper userDetailsContextMapper() {
        return new LdapUserDetailsContextMapper();
    }
}

并在 LdapUserDetailsContextMapper 内用 @Autowired 注释您的字段。