我正在尝试向Spring HttpSecurity
添加自定义过滤器。此过滤器必须检查用户名是否在外部提供的列表中,并作为Set
注入到过滤器中。
无论将过滤器放在何处,都不会调用其方法attemptAuthentication
。这是过滤器代码:
import java.io.IOException;
import java.util.Base64;
import java.util.Set;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
public class MyRoleFilter extends AbstractAuthenticationProcessingFilter {
final Set<String> authorisedUsers;
public WhoRoleFilter(String url, AuthenticationManager authenticationManager, Set<String> authorisedUsers) {
super(new AntPathRequestMatcher(url));
this.authorisedUsers= authorisedUsers;
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException, IOException, ServletException {
// In BASIC authentication user:password come as Base64 in the Authorization header
final String authorization = request.getHeader("Authorization");
final String[] userPasswd = new String(Base64.getDecoder().decode(authorization)).split(":");
// The docs of AbstractAuthenticationProcessingFilter says it must throw an exception in case authentication fails
// https://docs.spring.io/spring-security/site/docs/4.2.6.RELEASE/apidocs/org/springframework/security/web/authentication/AbstractAuthenticationProcessingFilter.html#attemptAuthentication-javax.servlet.http.HttpServletRequest-javax.servlet.http.HttpServletResponse-
if (userPasswd.length!=2)
throw new BadCredentialsException("Bad Credentials");
if (authorisedUsers.contains(userPasswd[0])) {
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(userPasswd[0], userPasswd[1]);
return this.getAuthenticationManager().authenticate(authRequest);
} else {
throw new BadCredentialsException("User has not the correct role");
}
}
}
这就是我试图将其添加到HttpSecurity
的方式:
@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/disabled")
.permitAll()
.anyRequest()
.authenticated()
.and()
.addFilterBefore(new MyRoleFilter("**/path/services/whatever/**", this.authenticationManager() ,myUserNamesSet), BasicAuthenticationFilter.class)
.httpBasic();
}
}
我不确定addFilterBefore()
在构建链中必须走到哪里。此外,除了用户名列表过滤器之外,还需要LDAP服务器上的标准用户+密码。 LDAP身份验证已经就位且工作正常。
更新,这是configureGlobal(AuthenticationManagerBuilder)
处的SecurityConfig
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
try {
auth.ldapAuthentication()
.userDnPatterns(ConfigurationProvider.get().getProperty(Property.PROP_LDAP_USER_BASE_DN))
.contextSource(contextSource())
.passwordCompare()
.passwordAttribute(ConfigurationProvider.get().getProperty(Property.PROP_LDAP_PASSWORD_ATTRIBUTE));
} catch (Exception exc) {
LOG.error(exc.getMessage(), exc);
}
}
答案 0 :(得分:0)
研究后回答我自己的问题。这是我必须实现SecurityConfig
和身份验证处理过滤器的方式,以便向使用LDAP来存储用户凭据的基本身份验证添加自定义角色检查。
@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private String Set<String> myUsers;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
myUsers = new HashSet<>(Arrays.asList("John","James","Jeremy"));
try {
auth.ldapAuthentication()
.userDnPatterns("ldap.user.base.dn")
.contextSource(contextSource())
.passwordCompare()
.passwordAttribute("ldap.password.attribute");
auth.authenticationEventPublisher(defaultAuthenticationEventPublisher());
} catch (Exception exc) {
// LOG.error(exc.getMessage(), exc);
}
}
@Override
@Autowired
public void setAuthenticationConfiguration(AuthenticationConfiguration authenticationConfiguration) {
super.setAuthenticationConfiguration(authenticationConfiguration);
}
@Override
@Autowired
public void setObjectPostProcessor(ObjectPostProcessor<Object> objectPostProcessor) {
super.setObjectPostProcessor(objectPostProcessor);
}
@Override
protected void configure(HttpSecurity http) {
try {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/disabled")
.permitAll()
.anyRequest()
.authenticated()
.and()
.addFilterAfter(new MyFilter("/services/my/path", this.authenticationManager(), myUsers), BasicAuthenticationFilter.class)
.httpBasic();
http.logout().deleteCookies("JSESSIONID")
.clearAuthentication(true)
.invalidateHttpSession(true);
} catch (Exception exc) {
// LOG.error(exc.getMessage(), exc);
}
}
}
请注意,我必须从successfulAuthentication
中覆盖AbstractAuthenticationProcessingFilter
,因为它一直试图执行重定向以查找包含目标URL的请求标头。
public class MyFilter extends AbstractAuthenticationProcessingFilter {
final Set<String> authorisedUsers;
public MyFilter(String url, AuthenticationManager authenticationManager, Set<String> authorisedUsers) {
super(new AntPathRequestMatcher(url));
this.authorisedUsers = authorisedUsers;
this.setAuthenticationManager(authenticationManager);
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException, IOException, ServletException {
// In BASIC authentication user:password come as Base64 in the Authorization header
final String authorization = request.getHeader("Authorization");
String authorizationBasic = authorization;
if (authorization.startsWith("Basic")) {
authorizationBasic = authorization.split(" ")[1];
}
final String[] userPasswd = new String(Base64.getDecoder().decode(authorizationBasic)).split(":");
// The docs of AbstractAuthenticationProcessingFilter says it must throw an exception in case authentication fails
// https://docs.spring.io/spring-security/site/docs/4.2.6.RELEASE/apidocs/org/springframework/security/web/authentication/AbstractAuthenticationProcessingFilter.html#attemptAuthentication-javax.servlet.http.HttpServletRequest-javax.servlet.http.HttpServletResponse-
if (userPasswd==null || userPasswd.length!=2)
throw new BadCredentialsException("Bad Credentials");
if (authorisedUsers.contains(userPasswd[0])) {
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(userPasswd[0], userPasswd[1]);
return getAuthenticationManager().authenticate(authRequest);
} else {
throw new BadCredentialsException("User " + userPasswd[0] + " has not the WHO role");
}
}
@Override
protected void successfulAuthentication(HttpServletRequest request,
HttpServletResponse response, FilterChain chain, Authentication authResult)
throws IOException, ServletException {
SecurityContextHolder.getContext().setAuthentication(authResult);
chain.doFilter(request, response);
}
}