2015-05-18 2 views
0

У меня есть webapp, который защищен Apache Shiro и работает нормально. Теперь я хочу добавить reCaptcha Goolge на мою страницу входа и не могу понять, как это сделать.Реализация reCaptcha с Apache Shiro

Качалка добавлена ​​и работает нормально, мне нужна помощь в том, как интегрировать ее с Shiro теперь, чтобы выполнить проверку, прежде чем продолжить аутентификацию пользователя.

Из того, что я собрал из docs, это будет сделано с помощью цепочки фильтров.

Так я это в мой shiro.ini:

[main] 
authc.failureKeyAttribute = shiroLoginFailure 
authc.loginUrl = /login.jsp 
authc.successUrl = /LogIn 
logout.redirectUrl = /login.jsp 
captcha = path.to.my.class.VerifyUserFilter 

... 

[urls] 
/login.jsp = captcha,authc 
/* = authc 

Я знаю, как реализовать логику проверки капчи. То, что я не знаю, это то, что класс VerifyUserFilter должен выглядеть в стороне от фактической логики проверки, чтобы сделать эту работу. По существу, все, что ему нужно сделать, это опубликовать в Google API, получить ответ, проанализировать его и на основе результата передать запрос на следующий фильтр или остановить, если верификация завершилась неудачно.

Прежде чем я разместил это, я решил дать ему последнюю попытку и потратил пару часов на то, чтобы пробовать разные вещи и в конечном итоге заставить его работать! Я все равно решил опубликовать этот вопрос в любом случае вместе с моим собственным ответом ниже, поскольку мне не удалось найти большую помощь при исследовании этого вопроса, а также выяснить, правильно ли я сделал то, что я сделал. Если есть лучший или более правильный способ сделать это, я бы хотел знать.

ответ

0

Вот как я решил это.

Сначала я создал мой shiro.ini следующим образом (соответствующие части):

[main] 
authc.failureKeyAttribute = shiroLoginFailure 
authc.loginUrl = /login.jsp 
authc.successUrl = /LogIn 
logout.redirectUrl = /login.jsp 
captcha = path.to.my.class.VerifyUserFilter 

... 

[urls] 
/login.jsp = captcha,authc 
/* = authc 

Затем я создал свой класс, расширяя FormAuthenticationFilter класс и перекрывая doFilterInternal метод, который считывает параметры, делает вызов к Google API, чтобы проверить ответ, а затем на основании результатов перенаправляется на страницу входа в систему, если верификация не выполнена или переходит к следующему элементу в цепочке фильтров - authc в этом случае.

Вот полная реализация моего класса:

import org.apache.shiro.web.util.WebUtils; 

public class VerifyUserFilter extends org.apache.shiro.web.filter.authc.FormAuthenticationFilter { 

    @Override 
    public void doFilterInternal(ServletRequest request, ServletResponse response, FilterChain chain) 
      throws ServletException, IOException { 
     org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(VerifyUserFilter.class); 
     if (isLoginSubmission(request, response)){ 
      String user = WebUtils.getCleanParam(request, "username"); 
      String verifId = WebUtils.getCleanParam(request, "g-recaptcha-response"); 
      log.debug("Verif ID: " + verifId); 
      if (verifId == null || "".equals(verifId)) {     
       log.warn("User " + user + " missed the captcha challenge and is returned to login page."); 
       saveRequestAndRedirectToLogin(request, response);     
      } else { 
       // Now do the verification of the captcha 
       final String url = "https://www.google.com/recaptcha/api/siteverify"; 
       final String secret = "6Lxxxxxxxxxxxxxx"; 
       // Send the POST request to the Google API 
       URL obj = new URL(url); 
       HttpsURLConnection con = (HttpsURLConnection)obj.openConnection(); 
       con.setRequestMethod("POST"); 
       String params = "secret=" + secret + "&response=" + verifId; 
       con.setDoOutput(true); 
       DataOutputStream wr = new DataOutputStream(con.getOutputStream()); 
       log.debug("Sending POST to " + url); 
       wr.writeBytes(params); 
       wr.flush(); 
       wr.close(); 
       // Get the response code 
       int respCode = con.getResponseCode(); 
       log.debug("Response code: " + respCode); 
       // Read in the response data 
       BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream())); 
       String line; 
       StringBuilder input = new StringBuilder(); 
       log.debug("Reading response data..."); 
       while ((line = in.readLine()) != null){ 
        input.append(line); 
       } 
       in.close(); 
       log.debug("Reponse data: " + input); 
       // Parse the json received to determine if the verif was successful 
       JsonReader jr = Json.createReader(new StringReader(input.toString())); 
       JsonObject jo = jr.readObject(); 
       jr.close();     
       if (jo.getBoolean("success")){     
        log.debug("User " + user + " is good to go, not a robot!"); 
        // Move on to the next filter 
        chain.doFilter(request, response); 
       } else { 
        // User did not solve the captcha, return to login page 
        log.warn("User " + user + " failed the captcha challenge and is returned to login page."); 
        saveRequestAndRedirectToLogin(request, response);      
       } 
      }     
     } else { 
      log.debug("Not a login attempt, carry on."); 
      chain.doFilter(request, response); 
     } 
    }    
}