Custom Authentication Manager con Spring Security y la configuración de Java

Estoy usando Spring Security con SpringMVC para crear una aplicación web (me referiré a esto como WebApp para mayor claridad) que se dirige a una aplicación existente (me referiré a esto como BackendApp).

Quiero delegar las responsabilidades de autenticación en BackendApp (para que no necesite sincronizar las dos aplicaciones).

Para implementar esto, me gustaría que la WebApp (corriendo la seguridad de spring) se comunique con BackendApp a través de REST con el nombre de usuario y la contraseña proporcionados por el usuario en un formulario y autenticación según si la respuesta de BackendApp es 200 OK o 401 no autorizado.

Entiendo que tendré que escribir un Administrador de autenticación personalizado para hacer esto. Sin embargo, soy muy nuevo para la spring y no puedo encontrar ninguna información sobre cómo implementarlo.

Creo que tendré que hacer algo como esto:

public class CustomAuthenticationManager implements AuthenticationManager{ @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { String username = authentication.getName(); String pw = authentication.getCredentials().toString(); // Code to make rest call here and check for OK or Unauthorised. // What do I return? } } 

¿Establezco authentication.setAuthenticated (true) si es correcto y falso si no, y eso es todo?

Una vez escrito esto, ¿cómo configuro la seguridad de spring para usar este administrador de autenticación usando un archivo de configuración java?

Gracias de antemano por cualquier ayuda.

Eche un vistazo a mi muestra a continuación. Debe devolver un UsernamePasswordAuthenticationToken. Contiene el director y las Autoridades otorgadas. Espero poder ayudar 🙂

 public Authentication authenticate(Authentication authentication) throws AuthenticationException { String username = authentication.getPrincipal() + ""; String password = authentication.getCredentials() + ""; User user = userRepo.findOne(username); if (user == null) { throw new BadCredentialsException("1000"); } if (user.isDisabled()) { throw new DisabledException("1001"); } if (!encoder.matches(password, user.getPassword())) { throw new BadCredentialsException("1000"); } List userRights = rightRepo.getUserRights(username); return new UsernamePasswordAuthenticationToken(username, password, userRights.stream().map(x -> new SimpleGrantedAuthority(x.getName())).collect(Collectors.toList())); } 

PD: userRepo y rightRepo son repositorys Spring-Data-JPA que acceden a mi User-DB personalizado

SpringSecurity JavaConfig:

 @Configuration @EnableWebMvcSecurity public class MySecurityConfiguration extends WebSecurityConfigurerAdapter { public MySecurityConfiguration() { super(false); } @Override protected AuthenticationManager authenticationManager() throws Exception { return new ProviderManager(Arrays.asList((AuthenticationProvider) new AuthProvider())); } } 

En su forma más simple:

 @Override public Authentication authenticate(Authentication auth) throws AuthenticationException { String username = auth.getName(); String password = auth.getCredentials().toString(); // to add more logic List grantedAuths = new ArrayList<>(); grantedAuths.add(new SimpleGrantedAuthority("ROLE_USER")); return new UsernamePasswordAuthenticationToken(username, password, grantedAuths); } 

Primero debe configurar la seguridad de Spring para usar su AuthenticationProvider personalizado. Por lo tanto, en spring-security.xml (o archivo de configuración equivalente) debe definir qué clase está implementando esta característica. Por ejemplo:

       

En segundo lugar, debe implementar AuthenticationProvider como en su ejemplo. Especialmente, el método de autenticación (Autenticación de autenticación) en el que debe estar su llamada de reposo. Por ejemplo:

 public Authentication authenticate(Authentication authentication) throws AuthenticationException { User user = null; try { //use a rest service to find the user. //Spring security provides user login name in authentication.getPrincipal() user = userRestService.loadUserByUsername(authentication.getPrincipal().toString()); } catch (Exception e) { log.error("Error loading user, not found: " + e.getMessage(), e); } if (user == null) { throw new UsernameNotFoundException(String.format("Invalid credentials", authentication.getPrincipal())); } else if (!user.isEnabled()) { throw new UsernameNotFoundException(String.format("Not found enabled user for username ", user.getUsername())); } //check user password stored in authentication.getCredentials() against stored password hash if (StringUtils.isBlank(authentication.getCredentials().toString()) || !passwordEncoder.isPasswordValid(user.getPasswordHash(), authentication.getCredentials().toString()) { throw new BadCredentialsException("Invalid credentials"); } //doLogin makes whatever is necesary when login is made (put info in session, load other data etc..) return doLogin(user); } 

Mi solución es casi la misma que la primera respuesta:

1) Necesita una clase que implemente el Proveedor de autenticación

 @Service @Configurable public class CustomAuthenticationProvider implements AuthenticationProvider { @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { // Your code of custom Authentication } } 

2) Enfrente de la primera respuesta , no necesita tener el código siguiente en su configuración de seguridad de la web si solo tiene este proveedor personalizado.

 @Override protected AuthenticationManager authenticationManager() throws Exception { return new ProviderManager(Arrays.asList((AuthenticationProvider) new AuthProvider())); } 

El problema es que Spring busca proveedores disponibles y usa el predeterminado si no se encuentra nada más. Pero como tienes la implementación de AuthenticationProvider, tu implementación será utilizada.