我遵循以下教程,以使Spring和Rest能够使用完整的安全性和无状态令牌。
http://captechconsulting.com/blog/jens-alm/versioned-validated-and-secured-rest-services-spring-40-4
我现在正在尝试将身份验证机制转换为使用Active Directory(ActiveDirectoryLdapAuthenticationProvider)。我的问题是我无法弄清楚如何到达UserDetails,因此可以使用loadUserByUsername(userName)方法。
下面是导致我出现问题的方法,注释行为过滤器提供了用户详细信息服务,但我无法弄清楚如何使用Active Directory身份验证获取此信息。
private Filter authenticationFilter() {
HeaderAuthenticationFilter headerAuthenticationFilter = new HeaderAuthenticationFilter();
//headerAuthenticationFilter.userDetailsService(userDetailsService());
headerAuthenticationFilter.headerUtil(headerUtil);
return headerAuthenticationFilter;
}
以下是我的Spring Security配置和使用的课程。
SecurityConfig
@Configuration
@EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private static final String ACCESS_DENIED_JSON = "{\"message\":\"You are not privileged to request this resource.\", \"access-denied\":true,\"cause\":\"AUTHORIZATION_FAILURE\"}";
private static final String UNAUTHORIZED_JSON = "{\"message\":\"Full authentication is required to access this resource.\", \"access-denied\":true,\"cause\":\"NOT AUTHENTICATED\"}";
@Autowired
private HeaderUtil headerUtil;
// @Autowired
// public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
// auth.inMemoryAuthentication().
//
// withUser("user").password("password").roles("USER").
//
// and().
//
// withUser("admin").password("password").roles("USER", "ADMIN");
// }
//
@Bean
public ActiveDirectoryLdapAuthenticationProvider activeDirectoryLdapAuthenticationProvider() {
ActiveDirectoryLdapAuthenticationProvider provider = new ActiveDirectoryLdapAuthenticationProvider("domain.com", "ldap://ad.domain.com:389");
provider.setConvertSubErrorCodesToExceptions(true);
provider.setUseAuthenticationRequestCredentials(true);
//provider.setAuthoritiesMapper( new NullAuthoritiesMapper()); // see http://comdynamics.net/blog/544/spring-security-3-integration-with-active-directory-ldap/
return provider;
}
@Autowired
protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(activeDirectoryLdapAuthenticationProvider());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
CustomAuthenticationSuccessHandler successHandler = new CustomAuthenticationSuccessHandler();
successHandler.headerUtil(headerUtil);
http.
addFilterBefore(corsFilter(), LogoutFilter.class).
addFilterBefore(authenticationFilter(), LogoutFilter.class).
csrf().disable().
formLogin().successHandler(successHandler).
loginProcessingUrl("/login").
and().
logout().
logoutSuccessUrl("/logout").
and().
sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).
and().
exceptionHandling().
accessDeniedHandler(new CustomAccessDeniedHandler()).
authenticationEntryPoint(new CustomAuthenticationEntryPoint()).
and().
authorizeRequests().
antMatchers(HttpMethod.POST, "/login").permitAll().
antMatchers(HttpMethod.POST, "/logout").authenticated().
// antMatchers(HttpMethod.GET, "/**").hasRole("USER").
// antMatchers(HttpMethod.POST, "/**").hasRole("ADMIN").
// antMatchers(HttpMethod.DELETE, "/**").hasRole("ADMIN").
antMatchers(HttpMethod.GET, "/**").authenticated().
antMatchers(HttpMethod.POST, "/**").authenticated().
antMatchers(HttpMethod.DELETE, "/**").authenticated().
anyRequest().authenticated();
}
private Filter authenticationFilter() {
HeaderAuthenticationFilter headerAuthenticationFilter = new HeaderAuthenticationFilter();
//headerAuthenticationFilter.userDetailsService(userDetailsService());
headerAuthenticationFilter.headerUtil(headerUtil);
return headerAuthenticationFilter;
}
private Filter corsFilter() {
return new SimpleCORSFilter();
}
private static class CustomAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
response.setContentType(Versions.V1_0);
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
PrintWriter out = response.getWriter();
out.print(ACCESS_DENIED_JSON);
out.flush();
out.close();
}
}
private static class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
response.setContentType(Versions.V1_0);
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
PrintWriter out = response.getWriter();
out.print(UNAUTHORIZED_JSON);
out.flush();
out.close();
}
}
private static class CustomAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
private HeaderUtil headerUtil;
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws ServletException, IOException {
try {
String token = headerUtil.createAuthToken(((LdapUserDetailsImpl) authentication.getPrincipal()).getUsername());
ObjectMapper mapper = new ObjectMapper();
ObjectNode node = mapper.createObjectNode().put("x-auth-token", token);
PrintWriter out = response.getWriter();
out.print(node.toString());
out.flush();
out.close();
} catch (GeneralSecurityException e) {
throw new ServletException("Unable to create the auth token", e);
}
clearAuthenticationAttributes(request);
}
private void headerUtil(HeaderUtil headerUtil) {
this.headerUtil = headerUtil;
}
}
}
HeaderAuthenticationFilter
public class HeaderAuthenticationFilter extends GenericFilterBean {
private UserDetailsService userDetailsService;
private HeaderUtil headerUtil;
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
UserDetails userDetails = loadUserDetails((HttpServletRequest) request);
SecurityContext contextBeforeChainExecution = createSecurityContext(userDetails);
try {
SecurityContextHolder.setContext(contextBeforeChainExecution);
if (contextBeforeChainExecution.getAuthentication() != null && contextBeforeChainExecution.getAuthentication().isAuthenticated()) {
String userName = (String) contextBeforeChainExecution.getAuthentication().getPrincipal();
headerUtil.addHeader((HttpServletResponse) response, userName);
}
filterChain.doFilter(request, response);
}
finally {
// Clear the context and free the thread local
SecurityContextHolder.clearContext();
}
}
private SecurityContext createSecurityContext(UserDetails userDetails) {
if (userDetails != null) {
SecurityContextImpl securityContext = new SecurityContextImpl();
Authentication authentication = new UsernamePasswordAuthenticationToken(userDetails.getUsername(), userDetails.getPassword(), userDetails.getAuthorities());
securityContext.setAuthentication(authentication);
return securityContext;
}
return SecurityContextHolder.createEmptyContext();
}
private UserDetails loadUserDetails(HttpServletRequest request) {
String userName = headerUtil.getUserName(request);
return userName != null
? userDetailsService.loadUserByUsername(userName)
: null;
}
public void userDetailsService(UserDetailsService userDetailsService2) {
this.userDetailsService = userDetailsService2;
}
public void headerUtil(HeaderUtil headerUtil) {
this.headerUtil = headerUtil;
}
}
答案 0 :(得分:0)
Spring LDAP有一个名为LdapUserDetailsService的东西,我将会说明这可能是你必须要做的事情。通常,Spring带有合理的默认值,我们只需连接正确的东西。