Rumah >Java >javaTutorial >Melaksanakan Pengesahan Token Satu Kali dengan Keselamatan Musim Bunga

Melaksanakan Pengesahan Token Satu Kali dengan Keselamatan Musim Bunga

DDD
DDDasal
2024-12-04 17:11:11689semak imbas

Implementing One-Time Token Authentication with Spring Security

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.

Memahami Token Satu Kali lwn Kata Laluan Sekali

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:

  • OTT tidak memerlukan persediaan pengguna awal
  • Token dijana dan dihantar oleh permohonan anda
  • Setiap token biasanya sah untuk sekali guna dan tamat tempoh selepas masa yang ditetapkan

Pelaksanaan Terbina dalam Tersedia

Spring Security menyediakan dua pelaksanaan OneTimeTokenService:

  1. InMemoryOneTimeTokenService:

    • Menyimpan token dalam ingatan
    • Sesuai untuk pembangunan dan ujian
    • Tidak sesuai untuk pengeluaran atau persekitaran berkelompok
    • Token hilang semasa aplikasi dimulakan semula
  2. JdbcOneTimeTokenService:

    • Menyimpan token dalam pangkalan data
    • Sesuai untuk kegunaan pengeluaran
    • Berfungsi dalam persekitaran berkelompok
    • Storan berterusan dengan pembersihan automatik

Menggunakan InMemoryOneTimeTokenService

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();
    }
}

Menggunakan JdbcOneTimeTokenService

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
);

Pelaksanaan Tersuai

Untuk lebih kawalan ke atas penjanaan token dan proses pengesahan, anda boleh membuat pelaksanaan tersuai:

1. Entiti Token dan Repositori

@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);
}

2. Perkhidmatan Token Tersuai

@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());
    }
}

Melaksanakan Penghantaran Token

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);
    }
}

Menyesuaikan URL dan Halaman

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();
    }
}

Pertimbangan Pengeluaran

Apabila menggunakan pengesahan OTT dalam pengeluaran:

  1. Pilih Perlaksanaan Yang Tepat

    • Gunakan JdbcOneTimeTokenService atau pelaksanaan tersuai untuk pengeluaran
    • InMemoryOneTimeTokenService hanya boleh digunakan untuk pembangunan/ujian
  2. 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();
    }
}
  1. Amalan Terbaik Keselamatan
    • Tetapkan masa tamat tempoh token yang sesuai (15 minit disyorkan)
    • Melaksanakan pengehadan kadar untuk penjanaan token
    • Gunakan HTTPS untuk semua titik akhir
    • Pantau percubaan pengesahan yang gagal
    • Pastikan token digunakan sekali dan tidak sah serta-merta selepas digunakan
    • Laksanakan pembersihan automatik token yang telah tamat tempoh
    • Gunakan penjanaan token rawak selamat untuk mengelakkan meneka

Bagaimana Ia Berfungsi

  1. Pengguna meminta token dengan menyerahkan alamat e-mel mereka
  2. Sistem menjana token selamat dan menghantar pautan ajaib melalui e-mel
  3. Pengguna mengklik pautan dan dialihkan ke halaman penyerahan token
  4. Sistem mengesahkan token dan mengesahkan pengguna jika sah

Kesimpulan

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:

  • Pilih pelaksanaan yang sesuai untuk persekitaran anda
  • Laksanakan penghantaran token selamat
  • Konfigurasikan tamat tempoh token yang betul
  • Ikuti amalan terbaik keselamatan
  • Buat pengendalian ralat dan ubah hala yang mesra pengguna
  • Laksanakan templat e-mel yang betul untuk penampilan profesional

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!

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn