Heim >Java >javaLernprogramm >Implementierung der einmaligen Token-Authentifizierung mit Spring Security
In der heutigen digitalen Landschaft ist die Bereitstellung sicherer und benutzerfreundlicher Authentifizierungsmethoden von entscheidender Bedeutung. Eine dieser immer beliebter werdenden Methoden ist die One-Time-Token-Authentifizierung (OTT), die oft als „magische Links“ implementiert wird, die per E-Mail verschickt werden. Spring Security 6.4.0 bietet robuste integrierte Unterstützung für die OTT-Authentifizierung, einschließlich gebrauchsfertiger Implementierungen. In diesem umfassenden Leitfaden erfahren Sie, wie Sie eine sichere OTT-Authentifizierung mithilfe integrierter Lösungen und benutzerdefinierter Implementierungen implementieren.
Bevor wir uns mit der Implementierung befassen, ist es wichtig zu verstehen, dass sich Einmal-Tokens (OTT) von Einmal-Passwörtern (OTP) unterscheiden. Während OTP-Systeme in der Regel eine Ersteinrichtung erfordern und für die Passwortgenerierung auf externe Tools angewiesen sind, sind OTT-Systeme aus Benutzersicht einfacher: Sie erhalten ein eindeutiges Token (normalerweise per E-Mail), mit dem sie sich authentifizieren können.
Zu den wichtigsten Unterschieden gehören:
Spring Security bietet zwei Implementierungen von OneTimeTokenService:
InMemoryOneTimeTokenService:
JdbcOneTimeTokenService:
So implementieren Sie die einfachere In-Memory-Lösung:
@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(); } }
Für Produktionsumgebungen verwenden Sie die JDBC-Implementierung:
@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(); } }
Erforderliche Tabellenstruktur für 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 );
Für mehr Kontrolle über den Token-Generierungs- und Validierungsprozess können Sie eine benutzerdefinierte Implementierung erstellen:
@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 kümmert sich nicht um die Token-Zustellung, daher müssen Sie sie implementieren:
@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 bietet mehrere Anpassungsoptionen:
@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(); } }
Beim Einsatz der OTT-Authentifizierung in der Produktion:
Wählen Sie die richtige Implementierung
E-Mail-Zustellung konfigurieren
@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(); } }
Die OTT-Unterstützung von Spring Security bietet eine solide Grundlage für die Implementierung einer sicheren, benutzerfreundlichen Authentifizierung. Unabhängig davon, ob Sie sich für die integrierten Implementierungen entscheiden oder eine benutzerdefinierte Lösung erstellen, können Sie Ihren Benutzern eine passwortlose Anmeldeoption anbieten und gleichzeitig hohe Sicherheitsstandards einhalten.
Denken Sie bei der Implementierung der OTT-Authentifizierung an Folgendes:
Indem Sie diesem Leitfaden folgen, können Sie ein sicheres und benutzerfreundliches OTT-Authentifizierungssystem implementieren, das die Anforderungen Ihrer Anwendung erfüllt und gleichzeitig die robusten Sicherheitsfunktionen von Spring Security nutzt.
Referenz: https://docs.spring.io/spring-security/reference/servlet/authentication/onetimetoken.html
Das obige ist der detaillierte Inhalt vonImplementierung der einmaligen Token-Authentifizierung mit Spring Security. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!