密码验证服务

时间:2017-09-08 12:04:30

标签: java spring string validation passwords

我需要编写一个密码验证服务,即接受某些规则:我编写了代码:

@Service
public class PasswordValidatonServiceImpl implements PasswordValidationService {

    public static final String EMPTY_OR_NULL_PASSWORD = "Password Should not be empty";
    public static final String ERROR_PASSWORD_LENGTH = "Password must be betwee 5 and 12 characters long.";
    public static final String ERROR_PASSWORD_CASE = "Password must only contain lowercase letters.";
    public static final String ERROR_LETTER_AND_DIGIT = "Password must contain both a letter and a digit.";
    public static final String ERROR_PASSWORD_SEQUENCE_REPEATED = "Password must not contain any sequence of characters immediately followed by the same sequence.";


    private Pattern checkCasePattern = Pattern.compile("[A-Z]");
    private Pattern checkLetterAndDigit = Pattern
            .compile("(?=.*[a-z])(?=.*[0-9])");
    private Pattern checkSequenceRepetition = Pattern.compile("(\\w{2,})\\1");

    /**
     * @param password
     * @return List<String> This method calls 4 more methods which validates
     *         password and return list of errors if any.
     */
    public List<String> validatePassword(String password) {
        List<String> failures = new ArrayList<String>();
        if (StringUtils.isEmpty(password)) {
            failures.add(EMPTY_OR_NULL_PASSWORD);
            return failures;
        } else {
            checkLength(password, failures);
            checkCase(password, failures);
            checkLetterAndDigit(password, failures);
            checkSequenceRepetition(password, failures);
            return failures;
        }
    }

    /**
     * @param password
     * @param failures
     *            This method will validate if there are any repeated character
     *            sequence, if found it will add error message to failures list.
     */
    private void checkSequenceRepetition(String password, List<String> failures) {
        Matcher matcher = checkSequenceRepetition.matcher(password);
        if (matcher.find()) {
            failures.add(ERROR_PASSWORD_SEQUENCE_REPEATED);
        }
    }

    /**
     * @param password
     * @param failures
     *            This method will validate both letters and characters in
     *            password, if not found add a error message to the failures
     *            list.
     */
    private void checkLetterAndDigit(String password, List<String> failures) {
        Matcher matcher = checkLetterAndDigit.matcher(password);
        if (!matcher.find()) {
            failures.add(ERROR_LETTER_AND_DIGIT);
        }
    }

    /**
     * @param password
     * @param failures
     *            This Method checks upper case and lower case letters in the
     *            password if there are any Upper case letters it will add error
     *            message to failures list.
     */
    private void checkCase(String password, List<String> failures) {
        Matcher matcher = checkCasePattern.matcher(password);
        if (matcher.find()) {
            failures.add(ERROR_PASSWORD_CASE);
        }
    }

    /**
     * @param string
     * @param failures
     *            This Method will checks the length of the string, if string is
     *            less than 5 or more than 12 characters then it will add error
     *            message into failures list
     */
    private void checkLength(String string, List<String> failures) {
        if (string.length() < 5 || string.length() > 12) {
            failures.add(ERROR_PASSWORD_LENGTH);
        }
    }
}

现在我的要求是使这个类是可扩展的,因此,将来,如果我想添加更多规则/取出一些规则,代码更改应该是最小的。我怎样才能做到这一点?任何建议表示赞赏。

3 个答案:

答案 0 :(得分:1)

您可以将PasswordValidationService定义为某种列表或一组新的抽象类PasswordRule。

这样,当且仅当每个PasswordRule都满足时,PasswordValidationService才会返回“密码有效”。

如果您要添加新规则,则只需将它们定义为新的PasswordRules并将其添加到PasswordValidationService实例中。

编辑:添加了示例代码

每个新规则需要实现的抽象类:

public abstract class PasswordRule{
    private String errorString;

    abstract public boolean check(String password){
        //implement the rule
    }

    public String getError(){
        return errorString;
    }
}

扩展PasswordRule抽象类的类,即密码不为空:

public class PasswordNotEmpty extends PasswordRule{
    private String errorString;

    public PasswordNotEmpty(){
        errorString = "Password Should not be empty";
    }

    public boolean check(String password){
        return StringUtils.isEmpty(password);
    }
}

最后是PasswordValidationService:

public class PasswordValidator implements PasswordValidationService{
    private Set<PasswordRule> rules = new HashSet<PasswordRules>();

    public PasswordValidator(PasswordRule... args){
        for(PasswordRule r : args)
            rules.add(r);
    }

    public List<String> validate(String password){
        List<String> failures = new ArrayList<String>();
        for(PasswordRule r : rules)
            if(!r.check(password))
                failures.add(r.getError());
        return failures;
    }
}

它的用法与此类似:

PasswordRule rule1 = new PasswordNotEmpty();
PasswordValidationService v = new PasswordValidator(rule1);
List<String> errors = v.validate("somePassword");

答案 1 :(得分:1)

首先不要将密码存储在 raise ValueError('invalid token in plural form: %s' % value) ValueError: invalid token in plural form: EXPRESSION 中,而是存储为String字符数组。这是出于安全原因。阅读更多内容。在这里:Why is char[] preferred over String for passwords?

其次,服务及其方法char[]应该返回布尔值描述密码本身的有效性。它将是:

isValid(char[] password)

就个人而言,我会创建一个包含当前验证策略的字段List或Set(如String,Enum ..)。应将这些条件规则添加到验证密码的服务实例中。

public boolean isValid(char[] password) { ... }

验证本身将根据方法private Set<PasswordValidationPolicy> passwordValidationPolicy; public void addPolicy(PasswordValidationPolicy policy) { this.passwordValidationPolicy.add(policy); } 中的列表或集合中的项目进行驱动。

isValid(...)

这只是众多可能实现中的一种。最后,您可以选择适合您项目的项目,并且应该尊重上述密码的常见做法。

答案 2 :(得分:0)

我建议您列出要在interface中使用的所有这些方法(如果需要更多generic方法,可以使用通用界面)。 然后在类中实现该接口,以便您需要导入它们。 总是覆盖你的方法,这将是非常好的。 正如Emanuele Giona写的那样,Abstract class也是一个很好的例子。必须覆盖抽象方法。