Настройка UserDetails с использованием службы без 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 не являются управляемыми компонентами, что делает невозможным @Autowired. Я хочу избежать LoadTimeWeaving, потому что использование этого очень усложнит развертывание - есть ли у меня другой выбор?
Я обнаружил две похожие проблемы: почему мое поле Spring @Autowired пусто? имеет ту же проблему в классе Controller, который можно превратить в управляемый компонент; оба других упомянутых решения не работали для меня (dataService всегда был нулевым) и Spring Boot, @Autowire, в неуправляемый класс с использованием @Configurable и переплетения времени загрузки снова рекомендует LoadTimeWeaving.
Я также нашел очевидные решения, в которых упоминается использование @Autowired в методе init, но я также не смог заставить его работать (пытаясь вызвать ContextMapper-конструктор с внедренным dataService)
1 ответ
Просто сделайте это бобом с пружиной.
@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
,