密码工具类-生成随机密码&校验密码强度是否满足要求

生成随机密码

符合密码强度的密码要求:

  • 至少有一个大写字母
  • 至少有一个小写字母
  • 至少有一个数字
  • 至少有一个特殊字符
  • 长度满足要求(通常为8-16位)
    // 大写字母
    private static final String UPPERCASE = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    // 小写字母
    private static final String LOWERCASE = "abcdefghijklmnopqrstuvwxyz";
    // 数字
    private static final String DIGITS = "0123456789";
    // 特殊字符(支持空格-下发密码明文时需要关注空格)
    private static final String SPECIAL_CHARS = "`~!@#$%^&*()-_=+[]{}\\|;:'\",.<>/? ";

    // 最小长度
    private static final int MIN_LENGTH = 8;

    // 最大长度
    private static final int MAX_LENGTH = 16;

    private static final SecureRandom random = new SecureRandom();
    /**
     * 生成随机密码
     * 满足强度要求
     * 长度随机
     *
     * @return 生成的密码
     */
    public static String generatePassword() {
        int length = MIN_LENGTH + random.nextInt(MAX_LENGTH - MIN_LENGTH);
        return generatePassword(length);
    }

    /**
     * 生成符合强密码要求的随机密码
     *
     * @param length 密码长度
     * @return 生成的密码
     * @throws IllegalArgumentException 长度不满足要求
     */
    public static String generatePassword(int length) {
        if (length < MIN_LENGTH || length > MAX_LENGTH) {
            throw new IllegalArgumentException("invalid password length.");
        }

        List<Character> passwordChars = new ArrayList<>();

        // 确保每类字符至少出现一次
        addRandomChar(passwordChars, UPPERCASE);
        addRandomChar(passwordChars, LOWERCASE);
        addRandomChar(passwordChars, DIGITS);
        addRandomChar(passwordChars, SPECIAL_CHARS);

        // 填充剩余字符
        String allChars = UPPERCASE + LOWERCASE + DIGITS + SPECIAL_CHARS;
        for (int i = 4; i < length; i++) {
            addRandomChar(passwordChars, allChars);
        }

        // 打乱字符顺序
        Collections.shuffle(passwordChars, random);

        // 构建密码字符串
        StringBuilder password = new StringBuilder();
        for (char c : passwordChars) {
            password.append(c);
        }

        return password.toString();
    }

    /**
     * 从指定字符串中随机选取一个字符并添加到密码列表中
     */
    private static void addRandomChar(List<Character> list, String charSet) {
        int index = random.nextInt(charSet.length());
        list.add(charSet.charAt(index));
    }

校验密码强度有效性

    // "^(?=.*[A-Z])(?=.*[a-z])(?=.*\\d)(?=.*[\\Q`~!@#$%^&*()-_=+[]{}\\|;:'\",.<>/? \\E]).{8,16}$"
    private static final Pattern PATTERN_VALID_PASSWORD = Pattern.compile("^" +
            "(?=.*[A-Z])" +
            "(?=.*[a-z])" +
            "(?=.*\\d)" +
            "(?=.*[" + Pattern.quote(SPECIAL_CHARS) + "])" +
            ".{" + MIN_LENGTH + "," + MAX_LENGTH + "}"
            + "$");

    /**
     * 判断密码强度是否满足要求
     * 长度为8-16位(可按照实际修改)
     * 必须包含大写字母,小写字母,数字,特殊字符
     *
     * @param input 带验证的密码明文
     * @return 是否满足强度要求
     */
    public static boolean isValid(String input) {
        if (input == null || input.isEmpty()) {
            return false;
        }
        return PATTERN_VALID_PASSWORD.matcher(input).matches();
    }

单元测试

package com.ysx.utils.security;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.stream.Stream;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

/**
 * @author youngbear
 * @email youngbear@aliyun.com
 * @date 2025-05-06 18:41
 * @blog <a href="https://blog.youkuaiyun.com/next_second">...</a>
 * @github <a href="https://github.com/YoungBear">...</a>
 * @description test for {@link PasswordUtils}
 */
class PasswordUtilsTest {

    private static final Logger LOGGER = LoggerFactory.getLogger(PasswordUtilsTest.class);

    @Test
    void generatePasswordTestForRandomLength() {
        String password = PasswordUtils.generatePassword();
        LOGGER.info("password: {}, length: {}.", password, password.length());
        assertTrue(password.length() >= 8);
        assertTrue(password.length() <= 16);
    }

    @Test
    void generatePasswordTestForSpecifiedLength() {
        int length = 10;

        String password = PasswordUtils.generatePassword(length);
        LOGGER.info("password: {}, length: {}.", password, password.length());
        assertEquals(length, password.length());
    }


    private static Stream<String> validPasswordProvider() {
        return Stream.of(
                "Abc@2025",
                "2025~xyZ",
                "(2020#Abc",
                " Abc2025",
                "~!@#$%Aa0",
                "2020$123$abc$ABC",
                "Aa0`2025@2026^Xy");
    }

    private static Stream<String> inValidPasswordProvider() {
        return Stream.of(
                null,
                "",
                "2025~xZ",
                "2025~xZ12ab34CD56",
                "(2020#abc",
                "(2020#ABC",
                "2020Abcd");
    }

    @ParameterizedTest(name = "#{index} - Run test with isValid = {0}")
    @MethodSource("validPasswordProvider")
    void test_isValid_input_valid(String input) {
        assertTrue(PasswordUtils.isValid(input));
    }

    @ParameterizedTest(name = "#{index} - Run test with isValid = {0}")
    @MethodSource("inValidPasswordProvider")
    void test_isValid_input_inValid(String input) {
        assertFalse(PasswordUtils.isValid(input));
    }
}

源代码地址

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值