Java 用ApacheShiro实现reCaptcha

Java 用ApacheShiro实现reCaptcha,java,web-applications,recaptcha,shiro,Java,Web Applications,Recaptcha,Shiro,我有一个用ApacheShiro保护的Web应用程序,并且运行良好。现在我想将Goolge的reCaptcha添加到我的登录页面,但我不知道如何做到这一点 验证码本身已经添加并且工作正常,我需要帮助的部分是如何将其与Shiro集成,以便在继续验证用户之前进行验证 从我收集的数据来看,这将通过一个过滤链来完成 所以我把它放进我的shiro.ini: [main] authc.failureKeyAttribute = shiroLoginFailure authc.loginUrl = /logi

我有一个用ApacheShiro保护的Web应用程序,并且运行良好。现在我想将Goolge的reCaptcha添加到我的登录页面,但我不知道如何做到这一点

验证码本身已经添加并且工作正常,我需要帮助的部分是如何将其与Shiro集成,以便在继续验证用户之前进行验证

从我收集的数据来看,这将通过一个过滤链来完成

所以我把它放进我的
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类需要什么样的外观才能使其工作。基本上,它所需要做的就是发布到GoogleAPI,获取响应,解析它,并根据结果将请求传递给下一个过滤器,或者在verif失败时停止


在我发布这篇文章之前,我决定做最后一次尝试,花了几个小时尝试不同的东西,最终让它工作起来!无论如何,我还是决定把这个问题和我自己的答案一起发布在下面,因为我在研究这个问题时找不到太多帮助,也不知道我所做的是否正确。如果有更好或更合适的方法,我想知道。

下面是我如何解决这个问题的

首先,我设置了我的
shiro.ini
,如下所示(相关部分):

然后,我通过扩展
FormAuthenticationFilter
类并重写读取参数的
doFilterInternal
方法,创建了我的
VerifyUserFilter
类,调用以验证响应,然后根据结果在verif失败时重定向到登录页面,或者在本例中转到筛选器链中的下一项-
authc

下面是my
VerifyUserFilter
类的完整实现:

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);
        }
    }              
}
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);
        }
    }              
}