Рубрики
Без рубрики

Клон Reddit с полным стеком – Spring Boot, React, Электронное приложение – Часть 3

Клон Reddit с полным стеком – Spring Boot, React, Электронное приложение – Введение в часть 3… С тегами react, java, веб-разработчик, машинопись.

Вступление

Добро пожаловать в часть 3 о создании клона Reddit с помощью Spring Boot и реагируйте.

Что мы строим в этой части?

  • Весенняя безопасность
  • Логика регистрации
  • Конечная точка регистрации
  • Кодировка Пароля
  • Электронные письма для активации
  • Конечная точка проверки/Активации

В части 2 мы создали все сущности и репозитории, необходимые в нашем бэкэнде!

Важные ссылки

Часть 1: Безопасность пружин 🔒

Давайте рассмотрим различные классы конфигурации, которые нам понадобятся. Внутри com.your-name.backend создайте новый пакет с именем config и добавьте следующие классы.

  • Безопасность: Обрабатывает конфигурацию безопасности для всего приложения и обрабатывает кодирование пароля перед сохранением его в базе данных.
package com.maxicb.backend.config;

    import org.springframework.context.annotation.Bean;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    import org.springframework.security.crypto.password.PasswordEncoder;

    @EnableWebSecurity
    public class Security extends WebSecurityConfigurerAdapter {

        @Override
        public void configure(HttpSecurity httpSecurity) throws Exception {
            httpSecurity.csrf().disable()
                    .authorizeRequests()
                    .antMatchers("/api/auth/**")
                    .permitAll()
                    .anyRequest()
                    .authenticated();
        }

        @Bean
        PasswordEncoder passwordEncoder() {
            return new BCryptPasswordEncoder();
        }
    }
  • Константы: Определяет ссылку на конечную точку активации, которая будет отправлена в электронном письме для активации учетной записи.
    package com.maxicb.backend.config;

    import lombok.experimental.UtilityClass;

    @UtilityClass
    public class Constants {
        public static final String EMAIL_ACTIVATION = "http://localhost:8080/api/auth/verify";
    }

Часть 2: Объект передачи данных Запроса на регистрацию – DTO 📃

Давайте рассмотрим различные классы DTO, которые нам понадобятся. Внутри com.your-name.backend создайте новый пакет с именем to и добавьте следующие классы.

  • Запрос на регистрацию: Определяет данные, которые наш сервер будет получать от клиента во время запроса на регистрацию.
    package com.maxicb.backend.dto;

    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class RegisterRequest {
        private String username;
        private String email;
        private String password;
    }

Часть 3. Создание исключения активации 📛

Давайте рассмотрим все пользовательские исключения, которые будут иметь наше приложение. Внутри com.your-name.backend создайте новый пакет с именем исключение и добавьте следующие классы.

  • Исключение ActivationException: Пользовательское исключение для обработки ошибок при отправке пользователям сообщений об активации
    package com.maxicb.backend.exception;

    public class ActivationException extends RuntimeException {
        public ActivationException(String message) {
            super(message);
        }
    }

Часть 4: Конструктор электронной почты 🛠

Давайте рассмотрим все различные классы построения электронной почты, которые будут иметь наше приложение. Внутри com.your-name.backend создайте новый пакет с именем service и добавьте следующие классы.

Нам также нужно добавить аннотацию @enableasync в наше серверное приложение.класс java для сокращения времени ожидания пользователя во время регистрации. Причина, по которой это необходимо, связана с зависанием конечной точки регистрации при отправке электронного письма с активацией учетной записи.

  • Серверное приложение – Обновлено:
    package com.maxicb.backend;

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.scheduling.annotation.EnableAsync;

    @SpringBootApplication
    @EnableAsync
    public class BackendApplication {

        public static void main(String[] args) {
            SpringApplication.run(BackendApplication.class, args);
        }

    }
  • Конструктор почты: Содержит логику создания вашей электронной почты с использованием шаблона HTML, который мы создадим позже.
    package com.maxicb.backend.service;

    import lombok.AllArgsConstructor;
    import org.springframework.stereotype.Service;
    import org.thymeleaf.TemplateEngine;
    import org.thymeleaf.context.Context;

    @Service
    @AllArgsConstructor
    public class MailBuilder {

        TemplateEngine templateEngine;

        String build(String message) {
            Context context = new Context();
            context.setVariable("body", message);
            return templateEngine.process("mailTemplate", context);
        }
    }
  • Почтовая служба: Содержит логику отправки пользователю электронного письма с активацией учетной записи.
    package com.maxicb.backend.service;

    import com.maxicb.backend.exception.ActivationException;
    import com.maxicb.backend.model.NotificationEmail;
    import lombok.AllArgsConstructor;
    import org.springframework.mail.MailException;
    import org.springframework.mail.javamail.JavaMailSender;
    import org.springframework.mail.javamail.MimeMessageHelper;
    import org.springframework.mail.javamail.MimeMessagePreparator;
    import org.springframework.scheduling.annotation.Async;
    import org.springframework.stereotype.Service;

    @Service
    @AllArgsConstructor

    public class MailService {

        JavaMailSender javaMailSender;
        MailBuilder mailBuilder;

        @Async
        void sendEmail(NotificationEmail notificationEmail) {
            MimeMessagePreparator messagePreparator = mimeMessage -> {
                MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage);
                messageHelper.setFrom("activation@redditclone.com");
                messageHelper.setTo(notificationEmail.getRecepient());
                messageHelper.setSubject(notificationEmail.getSubject());
                messageHelper.setText(mailBuilder.build(notificationEmail.getBody()));
            };
            try {
                javaMailSender.send(messagePreparator);
                System.out.println("Activation Email Sent");
            } catch (MailException e) {
                throw new ActivationException("Error sending activation email to " + notificationEmail.getRecepient());
            }
        }
    }

Часть 5: Шаблон электронной почты 📧

Давайте добавим шаблон электронной почты HTML, который наше приложение будет использовать для активации учетной записи. Внутри ресурсы.шаблоны создайте новый файл с именем mailTemplate.html , и добавьте следующий шаблон.









Часть 6: Служба аутентификации 🗝

Давайте рассмотрим все различные службы аутентификации, которые будут доступны в нашем приложении. Внутри com.your-name.backend.services добавьте следующий класс.

  • Служба авторизации: Содержит логику регистрации пользователя и хранения его в базе данных, кодирования паролей пользователей, проверки токенов и включения учетных записей.
    package com.maxicb.backend.service;

    import com.maxicb.backend.dto.RegisterRequest;
    import com.maxicb.backend.exception.ActivationException;
    import com.maxicb.backend.model.AccountVerificationToken;
    import com.maxicb.backend.model.NotificationEmail;
    import com.maxicb.backend.model.User;
    import com.maxicb.backend.repository.TokenRepository;
    import com.maxicb.backend.repository.UserRepository;
    import lombok.AllArgsConstructor;
    import org.springframework.security.crypto.password.PasswordEncoder;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;

    import java.time.Instant;
    import java.util.Optional;
    import java.util.UUID;

    import static com.maxicb.backend.config.Constants.EMAIL_ACTIVATION;

    @Service
    @AllArgsConstructor

    public class AuthService {

        UserRepository userRepository;
        PasswordEncoder passwordEncoder;
        TokenRepository tokenRepository;
        MailService mailService;
        MailBuilder mailBuilder;

        @Transactional
        public void register(RegisterRequest registerRequest) {
            User user = new User();
            user.setUsername(registerRequest.getUsername());
            user.setEmail(registerRequest.getEmail());
            user.setPassword(encodePassword(registerRequest.getPassword()));
            user.setCreationDate(Instant.now());
            user.setAccountStatus(false);

            userRepository.save(user);

            String token = generateToken(user);
            String message = mailBuilder.build("Welcome to React-Spring-Reddit Clone. " +
                    "Please visit the link below to activate you account : " + EMAIL_ACTIVATION + "/" + token);
            mailService.sendEmail(new NotificationEmail("Please Activate Your Account", user.getEmail(), message));
        }

        private String encodePassword(String password) {
            return passwordEncoder.encode(password);
        }

        private String generateToken(User user) {
            String token = UUID.randomUUID().toString();
            AccountVerificationToken verificationToken = new AccountVerificationToken();
            verificationToken.setToken(token);
            verificationToken.setUser(user);
            tokenRepository.save(verificationToken);
            return token;
        }

        public void verifyToken(String token) {
            Optional verificationToken = tokenRepository.findByToken(token);
            verificationToken.orElseThrow(() -> new ActivationException("Invalid Activation Token"));
            enableAccount(verificationToken.get());
        }

        public void enableAccount(AccountVerificationToken token) {
            String username = token.getUser().getUsername();
            User user = userRepository.findByUsername(username)
                    .orElseThrow(() -> new ActivationException("User not found with username: " + username));
            user.setAccountStatus(true);
            userRepository.save(user);
        }
    }

Часть 7: Контроллер аутентификации 🌐

Давайте добавим контроллер аутентификации, который будет использовать наше приложение. Внутри com.your-name.backend создайте новый пакет с именем контроллер и добавьте следующие классы..

  • AuthController: Определяет различные конечные точки для регистрации пользователя и активации учетной записи, когда пользователь посещает ссылку активации, отправленную по электронной почте.
    package com.maxicb.backend.controller;

    import com.maxicb.backend.dto.RegisterRequest;
    import com.maxicb.backend.service.AuthService;
    import lombok.AllArgsConstructor;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.*;

    @RestController
    @RequestMapping("/api/auth")
    @AllArgsConstructor
    public class AuthController {

        AuthService authService;

        @PostMapping("/register")
        public ResponseEntity register(@RequestBody RegisterRequest registerRequest) {
            authService.register(registerRequest);
            return new ResponseEntity<>(HttpStatus.OK);
        }

        @GetMapping("/verify/{token}")
        public ResponseEntity verify(@PathVariable String token) {
            authService.verifyToken(token);
            return new ResponseEntity<>("Account Activated", HttpStatus.OK);
        }
    }

Вывод 🔍

  • Чтобы убедиться, что все настроено правильно, вы можете запустить приложение и убедиться, что в консоли нет ошибок. В нижней части консоли вы должны увидеть вывод, аналогичный приведенному ниже
  • Если в консоли нет ошибок, вы можете проверить свою логику регистрации, отправив запрос post по адресу http://localhost:8080/api/auth/register со следующими данными
{
    "username": "test",
    "email": "test1@test.com",
    "password": "test12345"
}
  • Как только вы получите обратно статус 200 ОК, вы сможете проверить mailtrap.io входящие, чтобы найти отправленное электронное письмо с активацией. Ссылка должна выглядеть примерно так http://localhost:8080/api/auth/verify/{токен} , обязательно опустите < в конце ссылки. Переход по ссылке активирует учетную запись, и вы должны увидеть “Учетная запись активирована”, отображаемую в качестве ответа.

  • В этой статье мы добавили безопасность Spring, кодирование пароля пользователя, отправку электронных писем для активации учетной записи, а также создали логику и конечные точки для обработки регистрации учетной записи и активации.

  • После создания всех различных классов и написания всего кода структура вашего проекта должна выглядеть примерно так, как показано ниже

Следующая Часть 4

Оригинал: “https://dev.to/maxicb/full-stack-reddit-clone-spring-boot-react-electron-app-part-3-4a4n”