2017-09-08 66 views
0

我必須寫一個密碼驗證服務,這是accepct一定的規則要求:我寫了下面的代碼:密碼驗證服務

@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

即使違反了規則,您似乎也會檢查每條規則。如果違反其中一條規則,檢查一個有效的密碼並返回false會更容易嗎? – hamena314

+0

沒有得到你請你詳細說明 – user8579908

+0

大多數只包含小寫字母?長度在5到12個字符之間?挺嚇人的!考慮一下:https://nakedsecurity.sophos.com/2016/08/18/nists-new-password-rules-what-you-need-to-know/ – TheGreatContini

回答

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"); 
+0

示例代碼將不勝感激.. – user8579908

+0

我會用一些代碼編輯我的文章。 我建議你閱讀一些文檔:[Interfaces](https://docs.oracle.com/javase/tutorial/java/concepts/interface.html)和[Abstract Classes](https://docs.oracle.com) /javase/tutorial/java/IandI/abstract.html) –

+0

當然,這會幫助我.. – user8579908

1

首先不存儲密碼String但由於字符char[]的陣列。這是出於安全原因。閱讀更多f.e.這裏:Why is char[] preferred over String for passwords?

其次,該服務及其方法isValid(char[] password)應該返回布爾值來描述密碼本身的有效性。這將是:

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

就個人而言,我會創建一個字段列表或設置抱着驗證的現行政策(如字符串,枚舉..)。這些標準規則應該添加到驗證密碼的服務實例中。

private Set<PasswordValidationPolicy> passwordValidationPolicy; 

public void addPolicy(PasswordValidationPolicy policy) { 
    this.passwordValidationPolicy.add(policy); 
} 

驗證本身將根據該列表中的項目來驅動或設置方法isValid(...)

if (passwordValidationPolicy.contains(..)) { /* validate ... */} 

這只是許多可能的實現之一。最後,您應該選擇適合您的項目的項目,並且應該尊重上述密碼的常見做法。

+0

您可以請添加更多的密碼規則設置或列表的代碼段,我沒有得到我們如何能夠實現這一點..感謝您的幫助.. – user8579908

0

我建議你在interface(或者如果你需要更多的generic方法),列出你想要使用的所有這些方法。 然後在你的類中實現這個接口,所以你需要導入它們。 總是覆蓋你的方法,這將是非常好的。Emanuele Giona寫道: Abstract class也是一個很好的例子。抽象方法必須被覆蓋。

+0

你的意思是所有這些方法:checkLength(密碼,失敗); \t \t \t checkCase(password,failures); \t \t \t checkLetterAndDigit(password,failures); \t \t \t checkSequenceRepetition(password,failures);進入界面? – user8579908

+0

是的。你可以將它們全部列入接口中或作爲你將繼承的類中的抽象方法。所以你需要實現未實現的方法。閱讀關於抽象類和接口。我在我的答案中加入了超鏈接,也是Emanuele所做的 –