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

Весенняя Проверка Пользовательского Пароля

Автор оригинала: Dhananjay Singh.

Вступление

В наши дни политика паролей очень распространена и существует на большинстве онлайн-платформ. Хотя некоторым пользователям они на самом деле не нравятся, есть причина, по которой они существуют, – обеспечение безопасности паролей.

У вас наверняка был опыт работы с приложениями, навязывающими определенные правила для вашего пароля, такие как минимальное или максимальное разрешенное количество символов, включая цифры, заглавные буквы и т.д.

Независимо от того, насколько хороша система безопасности, если пользователь выберет слабый пароль, такой как “пароль”, конфиденциальные данные могут быть раскрыты. Хотя некоторые пользователи могут быть раздражены политикой паролей, они сохраняют данные вашего пользователя в безопасности, поскольку это делает атаки гораздо более неэффективными.

Чтобы реализовать это в наших приложениях на базе Spring, мы будем использовать Passay -библиотеку, созданную специально для этой цели, которая упрощает применение политик паролей в Java.

Пожалуйста, обратите внимание : В этом руководстве предполагается, что у вас есть базовые знания о фреймворке Spring, поэтому для краткости мы больше сосредоточимся на Passay.

Помимо политики паролей, хорошим и фундаментальным методом обеспечения безопасности является кодирование паролей .

Регистрационная форма

Самый простой способ начать со скелетного загрузочного проекта Spring, как всегда, – это использовать Spring Initializr .

Выберите предпочитаемую версию Spring Boot и добавьте зависимости Web и Thymeleaf :

После этого сгенерируйте его как проект Maven, и все готово!

Давайте определим простой Объект передачи данных , в который мы включим все атрибуты, которые мы хотим получить из нашей формы:

public class UserDto {

    @NotEmpty
    private String name;

    @Email
    @NotEmpty
    private String email;

    private String password;

Мы еще не аннотировали поле пароля, потому что для этого мы будем реализовывать пользовательскую аннотацию.

Затем у нас есть простой класс контроллера, который обслуживает форму регистрации и собирает ее данные при отправке с помощью GET/POST сопоставлений:

@Controller
@RequestMapping("/signup")
public class SignUpController {

    @ModelAttribute("user")
    public UserDto userDto() {
        return new UserDto();
    }

    @GetMapping
    public String showForm() {
        return "signup";
    }

    @PostMapping
    public String submitForm(@Valid @ModelAttribute("user") UserDto user, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            return "signup";
        }
        return "success";
    }

}

Сначала мы определили атрибут @ModelAttribute("пользователь") и присвоили ему UserDTO экземпляр. Это объект, в котором будет храниться информация после ее отправки.

Используя этот объект, мы можем извлечь данные и сохранить их в базе данных.

Метод showForm() возвращает строку со значением “регистрация”. Поскольку у нас есть Thymeleaf в вашем пути к классу, Весна будет искать “signup.html” в папке “Шаблоны” в разделе “Ресурсы”.

Аналогично, у нас есть отправить форму() ОПУБЛИКОВАТЬ сопоставление, которое проверит, есть ли в форме какие-либо ошибки. Если это произойдет, он перенаправится обратно в “signup.html” страница. В противном случае он перенаправит пользователя на страницу “успех”.

Thymeleaf -это современный серверный движок шаблонов Java для обработки и создания HTML, XML, JavaScript, CSS и текста. Это современная альтернатива старым механизмам создания шаблонов, таким как Java Server Pages (JSP) .

Давайте продолжим и определим “signup.html” страница:

Есть несколько вещей, на которые следует обратить внимание здесь:

  • th:действие – Атрибут действия ссылается на URL-адрес, который мы вызываем при отправке формы. Мы нацелены на сопоставление URL-адресов “регистрация” в нашем контроллере.
  • метод="отправить" – Атрибут метода относится к типу запроса, который мы отправляем. Это должно соответствовать типу запроса, определенному в методе submitForm () .
  • th:объект="${пользователь}" – Атрибут объекта ссылается на имя объекта, которое мы определили в контроллере ранее с помощью @ModelAttribute("пользователь") . Используя остальную часть формы, мы заполним поля экземпляра UserDTO , а затем сохраним экземпляр.

Git Essentials

Ознакомьтесь с этим практическим руководством по изучению Git, содержащим лучшие практики и принятые в отрасли стандарты. Прекратите гуглить команды Git и на самом деле изучите это!

У нас есть 3 других поля ввода, которые сопоставляются с именем , электронной почтой и паролем с помощью th:поле тег. Если в полях есть ошибки, пользователь будет уведомлен об этом с помощью тега th:ошибки .

Давайте запустим наше приложение и перейдем к http://localhost:8080/signup :

Пользовательская аннотация @validPassword

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

Поскольку мы можем применять различные политики и правила, давайте продолжим и определим пользовательскую аннотацию, которая проверяет действительный пароль, который мы будем использовать в нашем классе UserDTO .

Аннотации являются всего лишь метаданными для кода и не содержат никакой бизнес-логики. Они могут предоставлять только информацию об атрибуте (классе/методе/пакете/поле), для которого он определен.

Давайте создадим нашу @validPassword аннотацию:

@Documented
@Constraint(validatedBy = PasswordConstraintValidator.class)
@Target({ FIELD, ANNOTATION_TYPE })
@Retention(RUNTIME)
public @interface ValidPassword {

    String message() default "Invalid Password";

    Class[] groups() default {};

    Class[] payload() default {};
}

Как вы можете видеть, для создания аннотации мы используем ключевое слово @interface . Давайте взглянем на несколько ключевых слов и полностью разберемся в них, прежде чем продолжить:

  • @@Documented : простые аннотации маркеров, которые указывают, следует ли добавлять аннотации в Javadoc или нет.
  • @Ограничение : Помечает аннотацию как ограничение проверки компонента . Элемент , проверенный , указывает классы, реализующие ограничение. Мы создадим класс Password ConstraintValidator немного позже.
  • @Target : Здесь можно использовать наши аннотации. Если вы не укажете это, аннотацию можно разместить где угодно. В настоящее время наша аннотация может быть размещена поверх переменной экземпляра и на других аннотациях.
  • @Retention : Определяет, как долго должна храниться аннотация. Мы выбрали RUNTIME , чтобы он мог использоваться средой выполнения.

Чтобы использовать это в нашем UserDTO классе, просто аннотируйте поле пароля:

@ValidPassword
private String password;

Валидатор Пользовательских Ограничений Пароля

Теперь, когда у нас есть наша аннотация, давайте реализуем для нее логику проверки. Перед этим убедитесь, что у вас есть зависимость Passey Maven, включенная в ваш pom.xml файл:


    org.passay
    passay
    {$version}

Вы можете проверить наличие последней зависимости здесь .

Наконец, давайте напишем наш класс Password ConstraintValidator :

public class PasswordConstraintValidator implements ConstraintValidator {

    @Override
    public void initialize(ValidPassword arg0) {
    }

    @Override
    public boolean isValid(String password, ConstraintValidatorContext context) {
        PasswordValidator validator = new PasswordValidator(Arrays.asList(
            // at least 8 characters
            new LengthRule(8, 30),

            // at least one upper-case character
            new CharacterRule(EnglishCharacterData.UpperCase, 1),

            // at least one lower-case character
            new CharacterRule(EnglishCharacterData.LowerCase, 1),

            // at least one digit character
            new CharacterRule(EnglishCharacterData.Digit, 1),

            // at least one symbol (special character)
            new CharacterRule(EnglishCharacterData.Special, 1),

            // no whitespace
            new WhitespaceRule()

        ));
        RuleResult result = validator.validate(new PasswordData(password));
        if (result.isValid()) {
            return true;
        }
        List messages = validator.getMessages(result);

        String messageTemplate = messages.stream()
            .collect(Collectors.joining(","));
        context.buildConstraintViolationWithTemplate(messageTemplate)
            .addConstraintViolation()
            .disableDefaultConstraintViolation();
        return false;
    }
}

Мы реализовали интерфейс ConstraintValidator , который заставляет нас реализовать несколько методов.

Сначала мы создали объект Валидатор паролей , передав массив ограничений, которые мы хотим ввести в ваш пароль.

Ограничения объясняются сами собой:

  • Он должен быть длиной от 8 до 30 символов, как определено правилом Длины
  • Он должен содержать не менее 1 строчного символа, как определено правилом символов
  • Он должен содержать не менее 1 символа верхнего регистра, как определено правилом символов
  • Он должен содержать не менее 1 специального символа, как определено правилом символов
  • Он должен содержать не менее 1 значного символа, как определено правилом Символов
  • Он не должен содержать пробелов, как определено правилом Пробелов

Полный список правил, которые можно написать с помощью Assay, можно найти на официальном сайте .

Наконец, мы проверили пароль и вернули true , если он соответствует всем условиям. Если некоторые условия не выполняются, мы объединяем все сообщения об ошибках невыполненных условий в строку, разделенную символом”,”, а затем помещаем ее в контекст и возвращаем false .

Давайте запустим наш проект еще раз и введем неверный пароль, чтобы убедиться, что проверка работает:

Вывод

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

Как всегда, код для примеров, используемых в этой статье, можно найти на Github .