Mak*_*sim 27 java spring spring-security spring-security-ldap spring-boot
我正在使用Spring Boot构建一个与LDAP集成的应用程序.我能够成功连接到LDAP服务器并验证用户身份.现在我需要添加remember-me功能.我试图通过不同的帖子(这个)查看,但无法找到我的问题的答案.Spring Spring官方文件指出
如果您使用的身份验证提供程序不使用UserDetailsService(例如,LDAP提供程序),那么除非您的应用程序上下文中还有UserDetailsService bean,否则它将无法工作
在这里,我的工作代码有一些初步的想法,以添加记住我的功能:
WebSecurityConfig
import com.ui.security.CustomUserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.event.LoggerListener;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider;
import org.springframework.security.ldap.userdetails.UserDetailsContextMapper;
import org.springframework.security.web.authentication.RememberMeServices;
import org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices;
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
String DOMAIN = "ldap-server.com";
String URL = "ldap://ds.ldap-server.com:389";
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/ui/**").authenticated()
.antMatchers("/", "/home", "/UIDL/**", "/ui/**").permitAll()
.anyRequest().authenticated()
;
http
.formLogin()
.loginPage("/login").failureUrl("/login?error=true").permitAll()
.and().logout().permitAll()
;
// Not sure how to implement this
http.rememberMe().rememberMeServices(rememberMeServices()).key("password");
}
@Override
protected void configure(AuthenticationManagerBuilder authManagerBuilder) throws Exception {
authManagerBuilder
.authenticationProvider(activeDirectoryLdapAuthenticationProvider())
.userDetailsService(userDetailsService())
;
}
@Bean
public ActiveDirectoryLdapAuthenticationProvider activeDirectoryLdapAuthenticationProvider() {
ActiveDirectoryLdapAuthenticationProvider provider = new ActiveDirectoryLdapAuthenticationProvider(DOMAIN, URL);
provider.setConvertSubErrorCodesToExceptions(true);
provider.setUseAuthenticationRequestCredentials(true);
provider.setUserDetailsContextMapper(userDetailsContextMapper());
return provider;
}
@Bean
public UserDetailsContextMapper userDetailsContextMapper() {
UserDetailsContextMapper contextMapper = new CustomUserDetailsServiceImpl();
return contextMapper;
}
/**
* Impl of remember me service
* @return
*/
@Bean
public RememberMeServices rememberMeServices() {
// TokenBasedRememberMeServices rememberMeServices = new TokenBasedRememberMeServices("password", userService);
// rememberMeServices.setCookieName("cookieName");
// rememberMeServices.setParameter("rememberMe");
return rememberMeServices;
}
@Bean
public LoggerListener loggerListener() {
return new LoggerListener();
}
}
Run Code Online (Sandbox Code Playgroud)
CustomUserDetailsServiceImpl
public class CustomUserDetailsServiceImpl implements UserDetailsContextMapper {
@Autowired
SecurityHelper securityHelper;
Log ___log = LogFactory.getLog(this.getClass());
@Override
public LoggedInUserDetails mapUserFromContext(DirContextOperations ctx, String username, Collection<? extends GrantedAuthority> grantedAuthorities) {
LoggedInUserDetails userDetails = null;
try {
userDetails = securityHelper.authenticateUser(ctx, username, grantedAuthorities);
} catch (NamingException e) {
e.printStackTrace();
}
return userDetails;
}
@Override
public void mapUserToContext(UserDetails user, DirContextAdapter ctx) {
}
}
Run Code Online (Sandbox Code Playgroud)
我知道我需要以某种方式实现UserService,但不确定如何实现.
Vla*_*fer 32
使用LDAP配置RememberMe功能有两个问题:
我将逐步采取这些措施.
基于令牌的记住我feature(TokenBasedRememberMeServices)在身份验证期间以下列方式工作:
当用户想要回到服务并使用记住我的功能进行身份验证时,我们:
哈希检查过程是必需的,以确保没有人可以创建一个"假"记住我的cookie,这将让他们模仿另一个用户.问题是这个过程依赖于从我们的存储库加载密码的可能性 - 但是使用Active Directory这是不可能的 - 我们无法根据用户名加载明文密码.
这使得基于令牌的实现不适合与AD一起使用(除非我们开始创建一些包含密码或其他一些基于用户的秘密凭证的本地用户存储,并且我不建议这种方法,因为我不知道其他细节你的申请,虽然这可能是一个很好的方式).
另一个记得我实现是基于持久性令牌(PersistentTokenBasedRememberMeServices),它的工作原理如下(以简化的方式):
当用户想要验证我们时:
如您所见,不再需要密码,尽管我们现在需要一个令牌存储(通常是数据库,我们可以使用内存进行测试),而不是使用密码验证.
这让我们进入了配置部分.基于持久令牌的基本配置记住我看起来像这样:
@Override
protected void configure(HttpSecurity http) throws Exception {
....
String internalSecretKey = "internalSecretKey";
http.rememberMe().rememberMeServices(rememberMeServices(internalSecretKey)).key(internalSecretKey);
}
@Bean
public RememberMeServices rememberMeServices(String internalSecretKey) {
BasicRememberMeUserDetailsService rememberMeUserDetailsService = new BasicRememberMeUserDetailsService();
InMemoryTokenRepositoryImpl rememberMeTokenRepository = new InMemoryTokenRepositoryImpl();
PersistentTokenBasedRememberMeServices services = new PersistentTokenBasedRememberMeServices(staticKey, rememberMeUserDetailsService, rememberMeTokenRepository);
services.setAlwaysRemember(true);
return services;
}
Run Code Online (Sandbox Code Playgroud)
此实现将使用内存中的令牌存储,应该替换JdbcTokenRepositoryImpl为生产.所提供的UserDetailsService是负责为从记住我的cookie加载的用户ID所标识的用户加载附加数据.最简单的实现可能如下所示:
public class BasicRememberMeUserDetailsService implements UserDetailsService {
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return new User(username, "", Collections.<GrantedAuthority>emptyList());
}
}
Run Code Online (Sandbox Code Playgroud)
您还可以提供另一个UserDetailsService实现,根据您的需要从AD或内部数据库加载其他属性或组成员身份.它可能看起来像这样:
@Bean
public RememberMeServices rememberMeServices(String internalSecretKey) {
LdapContextSource ldapContext = getLdapContext();
String searchBase = "OU=Users,DC=test,DC=company,DC=com";
String searchFilter = "(&(objectClass=user)(sAMAccountName={0}))";
FilterBasedLdapUserSearch search = new FilterBasedLdapUserSearch(searchBase, searchFilter, ldapContext);
search.setSearchSubtree(true);
LdapUserDetailsService rememberMeUserDetailsService = new LdapUserDetailsService(search);
rememberMeUserDetailsService.setUserDetailsMapper(new CustomUserDetailsServiceImpl());
InMemoryTokenRepositoryImpl rememberMeTokenRepository = new InMemoryTokenRepositoryImpl();
PersistentTokenBasedRememberMeServices services = new PersistentTokenBasedRememberMeServices(internalSecretKey, rememberMeUserDetailsService, rememberMeTokenRepository);
services.setAlwaysRemember(true);
return services;
}
@Bean
public LdapContextSource getLdapContext() {
LdapContextSource source = new LdapContextSource();
source.setUserDn("user@"+DOMAIN);
source.setPassword("password");
source.setUrl(URL);
return source;
}
Run Code Online (Sandbox Code Playgroud)
这将让你记住我使用LDAP的功能,并提供将在RememberMeAuthenticationToken其中可用的加载数据SecurityContextHolder.getContext().getAuthentication().它还可以重用现有逻辑将LDAP数据解析为User对象(CustomUserDetailsServiceImpl).
作为一个单独的主题,问题中发布的代码也有一个问题,你应该替换:
authManagerBuilder
.authenticationProvider(activeDirectoryLdapAuthenticationProvider())
.userDetailsService(userDetailsService())
;
Run Code Online (Sandbox Code Playgroud)
有:
authManagerBuilder
.authenticationProvider(activeDirectoryLdapAuthenticationProvider())
;
Run Code Online (Sandbox Code Playgroud)
只应对userDetailsService进行调用,以便添加基于DAO的身份验证(例如,针对数据库),并且应该使用用户详细信息服务的实际实现来调用.您当前的配置可能会导致无限循环.
| 归档时间: |
|
| 查看次数: |
12272 次 |
| 最近记录: |