我需要编写一个密码验证服务,即接受某些规则:我编写了代码:
@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);
}
}
}
现在我的要求是使这个类是可扩展的,因此,将来,如果我想添加更多规则/取出一些规则,代码更改应该是最小的。我怎样才能做到这一点?任何建议表示赞赏。
答案 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也是一个很好的例子。必须覆盖抽象方法。