Dans le paysage numérique actuel, il est crucial de fournir des méthodes d'authentification sécurisées et conviviales. L'une de ces méthodes qui gagne en popularité est l'authentification One-Time Token (OTT), souvent mise en œuvre sous forme de « liens magiques » envoyés par courrier électronique. Spring Security 6.4.0 offre une prise en charge intégrée robuste de l'authentification OTT, y compris des implémentations prêtes à l'emploi. Dans ce guide complet, nous explorerons comment mettre en œuvre une authentification OTT sécurisée à l'aide de solutions intégrées et d'implémentations personnalisées.
Avant de plonger dans la mise en œuvre, il est important de comprendre que les jetons à usage unique (OTT) diffèrent des mots de passe à usage unique (OTP). Alors que les systèmes OTP nécessitent généralement une configuration initiale et s'appuient sur des outils externes pour la génération de mots de passe, les systèmes OTT sont plus simples du point de vue de l'utilisateur : ils reçoivent un jeton unique (généralement par e-mail) qu'ils peuvent utiliser pour s'authentifier.
Les principales différences incluent :
Spring Security fournit deux implémentations de OneTimeTokenService :
InMemoryOneTimeTokenService :
JdbcOneTimeTokenService :
Voici comment implémenter la solution en mémoire la plus simple :
@Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth .requestMatchers("/login/**", "/ott/**").permitAll() .anyRequest().authenticated() ) .formLogin(Customizer.withDefaults()) .oneTimeTokenLogin(Customizer.withDefaults()); // Uses InMemoryOneTimeTokenService by default return http.build(); } }
Pour les environnements de production, utilisez l'implémentation JDBC :
@Configuration @EnableWebSecurity public class SecurityConfig { @Autowired JdbcTemplate jdbcTemplate; @Bean public OneTimeTokenService oneTimeTokenService() { return new JdbcOneTimeTokenService(jdbcTemplate); } @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth .requestMatchers("/login/**", "/ott/**").permitAll() .anyRequest().authenticated() ) .formLogin(Customizer.withDefaults()) .oneTimeTokenLogin(Customizer.withDefaults()); return http.build(); } }
Structure de table requise pour JdbcOneTimeTokenService :
CREATE TABLE one_time_tokens ( token_value VARCHAR(255) PRIMARY KEY, username VARCHAR(255) NOT NULL, issued_at TIMESTAMP NOT NULL, expires_at TIMESTAMP NOT NULL, used BOOLEAN NOT NULL );
Pour plus de contrôle sur le processus de génération et de validation des jetons, vous pouvez créer une implémentation personnalisée :
@Entity @Table(name = "one_time_tokens") public class OneTimeToken { @Id @GeneratedValue private Long id; private String tokenValue; private String username; private LocalDateTime createdAt; private LocalDateTime expiresAt; private boolean used; // Getters and setters omitted for brevity } @Repository public interface OneTimeTokenRepository extends JpaRepository<OneTimeToken, Long> { Optional<OneTimeToken> findByTokenValueAndUsedFalse(String tokenValue); void deleteByExpiresAtBefore(LocalDateTime dateTime); }
@Service @Transactional public class PersistentOneTimeTokenService implements OneTimeTokenService { private static final int TOKEN_VALIDITY_MINUTES = 15; @Autowired private OneTimeTokenRepository tokenRepository; @Override public OneTimeToken generate(GenerateOneTimeTokenRequest request) { String tokenValue = UUID.randomUUID().toString(); LocalDateTime now = LocalDateTime.now(); OneTimeToken token = new OneTimeToken(); token.setTokenValue(tokenValue); token.setUsername(request.getUsername()); token.setCreatedAt(now); token.setExpiresAt(now.plusMinutes(TOKEN_VALIDITY_MINUTES)); token.setUsed(false); return return new DefaultOneTimeToken(token.getTokenValue(),token.getUsername(), Instant.now()); } @Override public Authentication consume(ConsumeOneTimeTokenRequest request) { OneTimeToken token = tokenRepository.findByTokenValueAndUsedFalse(request.getTokenValue()) .orElseThrow(() -> new BadCredentialsException("Invalid or expired token")); if (token.getExpiresAt().isBefore(LocalDateTime.now())) { throw new BadCredentialsException("Token has expired"); } token.setUsed(true); tokenRepository.save(token); UserDetails userDetails = loadUserByUsername(token.getUsername()); return new UsernamePasswordAuthenticationToken( userDetails, null, userDetails.getAuthorities()); } }
Spring Security ne gère pas la livraison des jetons, vous devrez donc l'implémenter :
@Component public class EmailMagicLinkHandler implements OneTimeTokenGenerationSuccessHandler { @Autowired private JavaMailSender mailSender; private final OneTimeTokenGenerationSuccessHandler redirectHandler = new RedirectOneTimeTokenGenerationSuccessHandler("/ott/check-email"); @Override public void handle(HttpServletRequest request, HttpServletResponse response, OneTimeToken token) throws IOException, ServletException { String magicLink = UriComponentsBuilder.fromHttpUrl(UrlUtils.buildFullRequestUrl(request)) .replacePath(request.getContextPath()) .replaceQuery(null) .fragment(null) .path("/login/ott") .queryParam("token", token.getTokenValue()) .toUriString(); SimpleMailMessage message = new SimpleMailMessage(); message.setTo(getUserEmail(token.getUsername())); message.setSubject("Your Sign-in Link"); message.setText("Click here to sign in: " + magicLink); mailSender.send(message); redirectHandler.handle(request, response, token); } }
Spring Security propose plusieurs options de personnalisation :
@Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth .requestMatchers("/login/**", "/ott/**").permitAll() .anyRequest().authenticated() ) .formLogin(Customizer.withDefaults()) .oneTimeTokenLogin(Customizer.withDefaults()); // Uses InMemoryOneTimeTokenService by default return http.build(); } }
Lors du déploiement de l'authentification OTT en production :
Choisissez la bonne mise en œuvre
Configurer la livraison des e-mails
@Configuration @EnableWebSecurity public class SecurityConfig { @Autowired JdbcTemplate jdbcTemplate; @Bean public OneTimeTokenService oneTimeTokenService() { return new JdbcOneTimeTokenService(jdbcTemplate); } @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth .requestMatchers("/login/**", "/ott/**").permitAll() .anyRequest().authenticated() ) .formLogin(Customizer.withDefaults()) .oneTimeTokenLogin(Customizer.withDefaults()); return http.build(); } }
La prise en charge OTT de Spring Security fournit une base solide pour la mise en œuvre d'une authentification sécurisée et conviviale. Que vous choisissiez les implémentations intégrées ou créiez une solution personnalisée, vous pouvez offrir à vos utilisateurs une option de connexion sans mot de passe tout en maintenant des normes de sécurité élevées.
Lors de la mise en œuvre de l'authentification OTT, n'oubliez pas de :
En suivant ce guide, vous pouvez mettre en œuvre un système d'authentification OTT sécurisé et convivial qui répond aux besoins de votre application tout en tirant parti des fonctionnalités de sécurité robustes de Spring Security.
Référence : https://docs.spring.io/spring-security/reference/servlet/authentication/onetimetoken.html
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!