Spring Security: authentification avec un UserDetailsService basé sur une base de données

Spring Security: authentification avec un UserDetailsService basé sur une base de données

1. Vue d'ensemble

Dans cet article, nous montrerons comment créer unUserDetailsService personnalisé basé sur une base de données pour l'authentification avec Spring Security.

2. UserDetailsService

L'interfaceUserDetailsService est utilisée pour récupérer les données relatives à l'utilisateur. Il a une méthode nomméeloadUserByUsername() qui peut être remplacée pour personnaliser le processus de recherche de l'utilisateur.

Il est utilisé par lesDaoAuthenticationProviderpour charger des détails sur l'utilisateur lors de l'authentification.

3. Le modèleUser

Pour stocker les utilisateurs, nous allons créer une entitéUser mappée à une table de base de données, avec les attributs suivants:

@Entity
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Column(nullable = false, unique = true)
    private String username;

    private String password;

    // standard getters and setters
}

4. Récupérer un utilisateur

Dans le but de récupérer un utilisateur associé à un nom d'utilisateur, nous allons créer une classeDAO en utilisantSpring Data en étendant l'interfaceJpaRepository:

public interface UserRepository extends JpaRepository {

    User findByUsername(String username);
}

5. LesUserDetailsService

Afin de fournir notre propre service utilisateur, nous devrons implémenter l'interfaceUserDetailsService.

Nous allons créer une classe appeléeMyUserDetailsService qui remplace la méthodeloadUserByUsername() de l'interface.

Dans cette méthode, nous récupérons l'objetUser en utilisant leDAO, et s'il existe, nous l'enveloppons dans un objetMyUserPrincipal, qui implémenteUserDetails, et le renvoie:

@Service
public class MyUserDetailsService implements UserDetailsService {

    @Autowired
    private UserRepository userRepository;

    @Override
    public UserDetails loadUserByUsername(String username) {
        User user = userRepository.findByUsername(username);
        if (user == null) {
            throw new UsernameNotFoundException(username);
        }
        return new MyUserPrincipal(user);
    }
}

Définissons la classeMyUserPrincipal comme suit:

public class MyUserPrincipal implements UserDetails {
    private User user;

    public MyUserPrincipal(User user) {
        this.user = user;
    }
    //...
}

6. Configuration du ressort

Nous allons démontrer les deux types de configurations Spring: XML et basées sur les annotations, qui sont nécessaires pour utiliser notre implémentationUserDetailsService personnalisée.

6.1. Configuration d'annotation

Tout ce que nous devons faire pour activer notreUserDetailsService s personnalisé est de l'ajouter à notre contexte d'application en tant que bean.

Puisque nous avons configuré notre classe avec l'annotation@Service, l'application la détectera automatiquement lors de l'analyse des composants et créera un bean à partir de cette classe. Par conséquent, il n’y a rien d’autre à faire ici.

Alternativement, nous pouvons:

  • configurez-le dans leauthenticationManager en utilisant la méthodeAuthenticationManagerBuilder#userDetailsService

  • définissez-le comme propriété dans un beanauthenticationProvider personnalisé, puis injectez-le en utilisant la fonctionAuthenticationManagerBuilder# authenticationProvider

6.2. Configuration XML

D'autre part, pour la configuration XML, nous devons définir un bean avec le typeMyUserDetailsService, et l'injecter dans le beanauthentication-provider de Spring:




    
        
        
    



    

7. Autres options d'authentification basées sur la base de données

LeAuthenticationManagerBuilder propose une autre méthode pour configurer l'authentification basée sur JDBC dans notre application.

Nous devrons configurer lesAuthenticationManagerBuilder.jdbcAuthentication avec une instanceDataSource. Si notre base de données suit lesSpring User Schema, alors les configurations par défaut nous conviendront bien.

Nous avons vu une configuration de base utilisant cette approche dansa previous post.

La sentitéJdbcUserDetailsManager résultant de cette configuration implémente leUserDetailsService too.

En conséquence, nous pouvons conclure que cette configuration est plus facile à implémenter, surtout si nous utilisons Spring Boot qui configure automatiquement lesDataSource pour nous.

Si nous avons besoin, de toute façon, d'un niveau de flexibilité plus élevé, en personnalisant exactement la manière dont l'application récupérera les détails de l'utilisateur, nous opterons pour l'approche que nous avons suivie dans ce tutoriel.

8. Conclusion

Pour résumer, dans cet article, nous avons montré comment créer unUserDetailsService basé sur Spring personnalisé et soutenu par des données persistantes.

L'implémentation peut être trouvée dansthe GitHub project - c'est un projet basé sur Maven, il devrait donc être facile à importer et à exécuter tel quel.