Rumah >Java >javaTutorial >Melaksanakan Pengesahan Token Satu Kali dengan Keselamatan Musim Bunga
Dalam landskap digital hari ini, menyediakan kaedah pengesahan yang selamat dan mesra pengguna adalah penting. Satu kaedah yang semakin popular ialah pengesahan One-Time Token (OTT), selalunya dilaksanakan sebagai "pautan ajaib" yang dihantar melalui e-mel. Spring Security 6.4.0 menyediakan sokongan terbina dalam yang teguh untuk pengesahan OTT, termasuk pelaksanaan sedia untuk digunakan. Dalam panduan komprehensif ini, kami akan meneroka cara melaksanakan pengesahan OTT selamat menggunakan kedua-dua penyelesaian terbina dalam dan pelaksanaan tersuai.
Sebelum memasuki pelaksanaan, adalah penting untuk memahami bahawa Token Satu Masa (OTT) berbeza daripada Kata Laluan Satu Masa (OTP). Walaupun sistem OTP lazimnya memerlukan persediaan awal dan bergantung pada alatan luaran untuk penjanaan kata laluan, sistem OTT lebih mudah dari perspektif pengguna - mereka menerima token unik (biasanya melalui e-mel) yang boleh mereka gunakan untuk mengesahkan.
Perbezaan utama termasuk:
Spring Security menyediakan dua pelaksanaan OneTimeTokenService:
InMemoryOneTimeTokenService:
JdbcOneTimeTokenService:
Berikut ialah cara untuk melaksanakan penyelesaian dalam ingatan yang lebih mudah:
@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(); } }
Untuk persekitaran pengeluaran, gunakan pelaksanaan 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(); } }
Struktur jadual yang diperlukan untuk 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 );
Untuk lebih kawalan ke atas penjanaan token dan proses pengesahan, anda boleh membuat pelaksanaan tersuai:
@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 tidak mengendalikan penghantaran token, jadi anda perlu melaksanakannya:
@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 menyediakan beberapa pilihan penyesuaian:
@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(); } }
Apabila menggunakan pengesahan OTT dalam pengeluaran:
Pilih Perlaksanaan Yang Tepat
Konfigurasikan Penghantaran E-mel
@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(); } }
Sokongan OTT Spring Security menyediakan asas yang kukuh untuk melaksanakan pengesahan selamat dan mesra pengguna. Sama ada anda memilih pelaksanaan terbina dalam atau mencipta penyelesaian tersuai, anda boleh menawarkan pengguna anda pilihan log masuk tanpa kata laluan sambil mengekalkan standard keselamatan yang tinggi.
Apabila melaksanakan pengesahan OTT, ingat untuk:
Dengan mengikuti panduan ini, anda boleh melaksanakan sistem pengesahan OTT yang selamat dan mesra pengguna yang memenuhi keperluan aplikasi anda sambil memanfaatkan ciri keselamatan Spring Security yang teguh.
Rujukan: https://docs.spring.io/spring-security/reference/servlet/authentication/onetimetoken.html
Atas ialah kandungan terperinci Melaksanakan Pengesahan Token Satu Kali dengan Keselamatan Musim Bunga. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!