2017-09-08 11 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

ルールの違反があっても、すべてのルールをチェックしているようです。有効なパスワードをチェックし、ルールの1つに違反した場合はすぐに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のセットとして定義することができます。

このように、PasswordValidationServiceは、すべてのPasswordRuleが満たされている場合にのみ、「password is valid」を返します。

新しいルールを追加する場合は、新しいパスワードルールとして定義し、それらをPasswordValidationServiceインスタンスに追加するだけです。

EDIT:すべての新しいルールを実装する必要があります追加のサンプルコード

抽象クラス:

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)Javaの –

+0

確かに、それは私を助けてくれるでしょう.. – user8579908

1

はまずStringではなく、文字char[]の配列としてパスワードを保管しないでください。セキュリティ上の理由によるものです。 f。ここで:Why is char[] preferred over String for passwords?

第2に、サービスとその方法isValid(char[] password)は、パスワードそのものの有効性を記述するブール値を返すものとします。

個人的には、現在の検証ポリシー(String、Enum ..)を保持するフィールドListまたはSetを作成します。これらの基準ルールは、パスワードを検証するサービスのインスタンスに追加する必要があります。

private Set<PasswordValidationPolicy> passwordValidationPolicy; 

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

検証自体は、方法isValid(...)でリストまたはセット内のアイテム応じて駆動されることになります。

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

これは多くの可能な実装の1つに過ぎません。最後に、あなたのプロジェクトに合ったものを選ぶことはあなた次第であり、上記のパスワードに関する一般的な慣行を尊重すべきです。

+0

パスワードのルールのセットまたはリストのコードスニペットを少し追加してもらえますか?私はどのようにこのことを達成できるのですか?助けてくれてありがとうございます。 – user8579908

0

interfaceで使用したいこれらすべての方法をリストアップすることをお勧めします(例:genericのメソッドなどが必要な場合は汎用インターフェースかもしれません)。 そして、そのインターフェイスをクラスに実装して、それらをインポートする必要があります。 あなたのメソッドを常にオーバーライドしてください。本当にうれしいでしょう。Emanuele Gionaが書いたように、 Abstract classも素晴らしい例です。抽象メソッドはオーバーライドする必要があります。

+0

あなたはこれらすべての方法を意味します:checkLength(パスワード、失敗); \t \t \t checkCase(パスワード、失敗); \t \t \t checkLetterAndDigit(パスワード、失敗); \t \t \t checkSequenceRepetition(パスワード、失敗);インターフェイスに? – user8579908

+0

はい。これらをすべてインターフェイスにリストするか、継承するクラスの抽象メソッドとしてリストします。したがって、実装されていないメソッドを実装する必要があります。抽象クラスとインタフェースについて読んでください。私は私の答えにハイパーリンクを付けました。また、Emanueleはやった –

関連する問題