为了使Spring和Rest能够使用完全安全和无状态令牌,我遵循以下教程。ActiveDirectoryLdapAuthenticationProvider:获取用户详细信息
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 Configuration和使用的类。
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;
}
}
所以UserDetailsService不是通过oringally自动装配的。这是我加入试图解决我的问题。我也尝试过使用LdapUserDetailsService,但我不确定如何正确获取它的一个实例。当安全配置被创建并且使用由@EnableWebMvcSecurity标签证明的方法时,当前的UserDetailsService对象被定义。 – 2014-11-21 18:41:52