Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/maven/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在Spring Security中集成JCaptcha_Spring_Maven_Spring Security_Weblogic_Captcha - Fatal编程技术网

如何在Spring Security中集成JCaptcha

如何在Spring Security中集成JCaptcha,spring,maven,spring-security,weblogic,captcha,Spring,Maven,Spring Security,Weblogic,Captcha,在开始回答之前,我知道有ReCaptcha,它更简单更容易,但我不能使用它。生产服务器未联机。我们开始吧 我在maven项目上使用SpringMVC3和SpringSecurity,并将weblogic用作web服务器(开发时使用jetty)。关于这一点,我会非常详细 在查看我的配置和文件之前,我想向您展示我的问题列表: 在JCaptcha之前,我尝试过使用相同的编码结构进行ReCaptcha,效果很好 logger.debug根本不出现在CaptchaCaptureFilter类和/或Cap

在开始回答之前,我知道有ReCaptcha,它更简单更容易,但我不能使用它。生产服务器未联机。我们开始吧

我在maven项目上使用SpringMVC3和SpringSecurity,并将weblogic用作web服务器(开发时使用jetty)。关于这一点,我会非常详细

在查看我的配置和文件之前,我想向您展示我的问题列表:

  • 在JCaptcha之前,我尝试过使用相同的编码结构进行ReCaptcha,效果很好
  • logger.debug根本不出现在CaptchaCaptureFilter类和/或CaptchaVerifierFilter类中(而出现在ArtajasAuthenticationProvider类中)
  • 我可以看到验证码图像,但不管答案是什么,它总是无效的
  • 在当前状态下,它在jetty和weblogic中都不起作用,但是如果我将自定义过滤器位置更改为下面的位置,它只在jetty中起作用

    <custom-filter ref="captchaCaptureFilter" position="FIRST"/>
    <custom-filter ref="captchaVerifierFilter" after="FIRST"/>
    
    captchavifierfilter.java

    public class CaptchaCaptureFilter extends OncePerRequestFilter {
    
    protected Logger logger = Logger.getLogger(CaptchaCaptureFilter.class);
    private String userCaptchaResponse;
    private HttpServletRequest request;
    
    @Override
    public void doFilterInternal(HttpServletRequest req, HttpServletResponse res,
                                 FilterChain chain) throws IOException, ServletException {
    
        logger.debug("Captcha capture filter");
    
        // Assign values only when user has submitted a Captcha value.
        // Without this condition the values will be reset due to redirection
        // and CaptchaVerifierFilter will enter an infinite loop
        if (req.getParameter("jcaptcha") != null) {
            request = req;
            userCaptchaResponse = req.getParameter("jcaptcha");
        }
    
        logger.debug("userResponse: " + userCaptchaResponse);
    
        // Proceed with the remaining filters
        chain.doFilter(req, res);
    }
    
    public String getUserCaptchaResponse() {
        return userCaptchaResponse;
    }
    
    public void setUserCaptchaResponse(String userCaptchaResponse) {
        this.userCaptchaResponse = userCaptchaResponse;
    }
    
    public HttpServletRequest getRequest() {
        return request;
    }
    
    public void setRequest(HttpServletRequest request) {
        this.request = request;
    }
    }
    
    public class CaptchaVerifierFilter extends OncePerRequestFilter {
    
    protected Logger logger = Logger.getLogger(CaptchaVerifierFilter.class);
    private String failureUrl;
    private CaptchaCaptureFilter captchaCaptureFilter;
    
    // Inspired by log output: AbstractAuthenticationProcessingFilter.java:unsuccessfulAuthentication:320)
    // Delegating to authentication failure handlerorg.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler@15d4273
    private SimpleUrlAuthenticationFailureHandler failureHandler = new SimpleUrlAuthenticationFailureHandler();
    
    @Override
    public void doFilterInternal(HttpServletRequest req, HttpServletResponse res,
                                 FilterChain chain) throws IOException, ServletException {
    
        logger.debug("Captcha verifier filter");
        logger.debug("userResponse: " + captchaCaptureFilter.getUserCaptchaResponse());
    
        // Assign values only when user has submitted a Captcha value
        if (captchaCaptureFilter.getUserCaptchaResponse() != null) {
    
            // Send HTTP request to validate user's Captcha
            boolean captchaPassed = SimpleImageCaptchaServlet.validateResponse(captchaCaptureFilter.getRequest(), captchaCaptureFilter.getUserCaptchaResponse());
    
            // Check if valid
            if (!captchaPassed) {
                logger.debug("Captcha is invalid!");
    
                // Redirect user to login page
                failureHandler.setDefaultFailureUrl(failureUrl);
                failureHandler.onAuthenticationFailure(req, res, new BadCredentialsException("Captcha invalid! " + captchaCaptureFilter.getRequest() + " " + captchaCaptureFilter.getUserCaptchaResponse()));
    
            } else {
                logger.debug("Captcha is valid!");
            }
    
            // Reset Captcha fields after processing
            // If this method is skipped, everytime we access a page
            // CaptchaVerifierFilter will infinitely send a request to the Google Captcha service!
            resetCaptchaFields();
        }
    
        // Proceed with the remaining filters
        chain.doFilter(req, res);
    }
    
    /**
     * Reset Captcha fields
     */
    public void resetCaptchaFields() {
        captchaCaptureFilter.setUserCaptchaResponse(null);
    }
    
    public String getFailureUrl() {
        return failureUrl;
    }
    
    public void setFailureUrl(String failureUrl) {
        this.failureUrl = failureUrl;
    }
    
    public CaptchaCaptureFilter getCaptchaCaptureFilter() {
        return captchaCaptureFilter;
    }
    
    public void setCaptchaCaptureFilter(CaptchaCaptureFilter captchaCaptureFilter) {
        this.captchaCaptureFilter = captchaCaptureFilter;
    }
    }
    
    最后但并非最不重要的一点是login.jsp

    <%@ taglib prefix='c' uri='http://java.sun.com/jstl/core_rt' %>
    
    <form id="login" name="f" action="<c:url value='/j_spring_security_check'/>" method="POST">
      <div class="container">
    
        <div class="content">
            <div class="row">
                <div class="login-form">
                    <h3>Login</h3>
                    <br />
                      <fieldset>
                           <div class="clearfix">
                                username: ecr
                                <input type="text" name='j_username' value='<c:if test="${not empty param.login_error}"><c:out value="${SPRING_SECURITY_LAST_USERNAME}"/></c:if>' placeholder="username@artajasa.co.id">
                           </div>
                           <div class="clearfix">
                               password: ecr123
                               <input type="password" name='j_password' placeholder="password">
                           </div>
                           <div class="clearfix">
                               <img src="../../jcaptcha.jpg" />
                               <br />
                               <input type="text" name="jcaptcha" placeholder="masukkan captcha" />
                           </div>
                           <br />
                           <button class="btn btn-primary" type="submit"><i class="icon-lock"></i> Sign in</button>
                       </fieldset>
                </div>
            </div>
        </div>
         <br />
         <c:if test="${not empty error}">
                <div class="alert alert-error">
                <button type="button" class="close" data-dismiss="alert"><i class="icon-remove"></i></button>
                Login Failed, try again.<br />
                <c:out value="${sessionScope['SPRING_SECURITY_LAST_EXCEPTION'].message}"/>
                </div>
              </c:if>
      </div>
    
    
    登录
    
    用户名:ecr 密码:ECR223

    登录
    登录失败,请重试。

    问题解决了!我找到了答案。所以我们根本不需要CaptchaVerifierFilter。我在AuthenticationProvider中验证验证码

    这些是更改列表:

    在spring-security.xml中,这个

    <!--JCaptcha Filtering-->
    <custom-filter ref="captchaCaptureFilter" before="FORM_LOGIN_FILTER"/>
    <custom-filter ref="captchaVerifierFilter" after="FORM_LOGIN_FILTER"/>
    
    
    
    变成这个

    <!--JCaptcha Filtering-->
    <custom-filter ref="captchaCaptureFilter" before="FORM_LOGIN_FILTER"/>
    
    
    
    除去

    <!-- For verifying CAPTCHA fields -->
    <!-- Private key is assigned by the JCaptcha service -->
    <beans:bean id="captchaVerifierFilter" class="com.util.CaptchaVerifierFilter"
      p:failureUrl="/session/loginfailed/"
      p:captchaCaptureFilter-ref="captchaCaptureFilter"/>
    
    
    
    在这里验证验证码

    <beans:bean id="customAuthenticationProvider" class="com.pusilkom.artajasa.ecr.backend.util.MyAuthenticationProvider"
                p:captchaCaptureFilter-ref="captchaCaptureFilter"/>
    

    在Spring安全认证之前,我又尝试了一种验证JCaptcha的方法。首先,JCaptcha将得到验证,如果这是正确的,控制将转到Spring安全验证。我没有在security-context.xml中添加CaptchaCaptureFilter

    下面是我试过的。它工作正常

    public String login() {
        this.captchaPassed = false;
    
        // Check if captcha entered is correct. If yes then only proceed with
        // Spring Security Authentication
        this.captchaPassed = checkLoginCaptcha();
    
        if (captchaPassed) {
            boolean success = authenticationService.login(userName, password);
    
            if (success) {
                StringBuilder userNameBuilder = new StringBuilder();
                userNameBuilder.append(userName);
                FacesContext.getCurrentInstance().getExternalContext()
                        .getSessionMap()
                        .put("USER_NAME_PARAM", userNameBuilder.toString());
                return ApplicationConstants.HOME_PAGE;
            } else {
                this.message = "Wrong Username or Password Entered. Please LOGIN again.";
                this.userName = null;
                this.password = null;
                this.captchaString = null;
    
                return ApplicationConstants.LOGIN_PAGE;
            }
        } else {
            this.message = "Invalid captcha entered. Please LOGIN again.";
            return ApplicationConstants.LOGIN_PAGE;
        }
    }
    
    public boolean checkLoginCaptcha() {
    
        HttpServletRequest req = (HttpServletRequest) FacesContext
                .getCurrentInstance().getExternalContext().getRequest();
        String str = null;
        boolean flag = false;
    
        try {
            str = req.getParameter("loginForm:jcaptchaString");
    
            if (str != null) {
                flag = SimpleImageCaptchaServlet.validateResponse(req, str);
            }
        } catch (Exception e) {
            e.printStackTrace();
            flag = false;
        }
    
        return flag;
    }
    

    我不确定这是否是正确的做法,但它对我来说是完美的。 我创建了与您相同的类,只对过滤器类代码进行了少量更改,对security context.xml进行了少量更改

  • 我在CaptchaCaptureFilter中验证captcha,并将验证结果存储在变量iscaptchaPassed中,该变量是CaptchaCaptureFilter中的一个属性。随着 iscaptchaPassed我还将响应存储为CaptCharResponse,以检查稍后在CaptchaVerifierFilter中是否为null
  • 公共类CaptchaCaptureFilter扩展了OncePerRequestFilter{

    private String captchaResponse;
    
    private boolean iscaptchaPassed;
    
    protected Logger logger = LoggerFactory.getLogger(Filter.class);
    
    private CaptchaCaptureFilter captchaCaptureFilter;
    
    private String failureUrl;
    
    //getters and setters**strong text**
    
    private SimpleUrlAuthenticationFailureHandler failureHandler = new SimpleUrlAuthenticationFailureHandler();
    
    @Override
    public void doFilterInternal(HttpServletRequest req, HttpServletResponse res,FilterChain chain) throws IOException, ServletException {
    
        //logger.info("Captcha verifier filter");
        boolean captchaPassed=captchaCaptureFilter.getIscaptchaPassed();
        String captchaResponse=captchaCaptureFilter.getCaptchaResponse();
        //logger.info("captcha captured :"+captchaResponse+" validation result of captcha : " +captchaPassed);
    
        if(captchaResponse!=null)
        {
            if(captchaPassed)
            {
                logger.info("Captcha is valid!");
            }
            else
            {
                logger.info("Captcha is invalid!");
                failureHandler.setDefaultFailureUrl(failureUrl);
                failureHandler.onAuthenticationFailure(req, res, new BadCredentialsException("Captcha invalid!"));
            }
            resetCaptchaFields();   
        }
    
        chain.doFilter(req, res);           
    }
    
    /** 
     * Reset Captcha fields
     */
    public void resetCaptchaFields() {
        captchaCaptureFilter.setCaptchaResponse(null);
        captchaCaptureFilter.setIscaptchaPassed(false);;
    }
    
    //二传手和接球手

    @Override
    public void doFilterInternal(HttpServletRequest req, HttpServletResponse res,FilterChain chain) throws IOException, ServletException {
    
        logger.info("Captcha capture filter");
    
        String captcha_Response=req.getParameter("jcaptcha");
        logger.info("response captcha captured : " +captcha_Response);
    
        if(captcha_Response!=null)
        {
            iscaptchaPassed = SimpleImageCaptchaServlet.validateResponse(req, req.getParameter("jcaptcha"));
            captchaResponse=captcha_Response;
            logger.info("isCaptchaPassed value is "+iscaptchaPassed);
        }
    
        // Proceed with the remaining filters
        chain.doFilter(req, res);
    }
    
  • 读取CaptchaVerifyFilter中注入的captchaCaptureFilter的值,并按以下方式处理
  • 公共类CaptchaVerifierFilter扩展了OncePerRequestFilter{

    private String captchaResponse;
    
    private boolean iscaptchaPassed;
    
    protected Logger logger = LoggerFactory.getLogger(Filter.class);
    
    private CaptchaCaptureFilter captchaCaptureFilter;
    
    private String failureUrl;
    
    //getters and setters**strong text**
    
    private SimpleUrlAuthenticationFailureHandler failureHandler = new SimpleUrlAuthenticationFailureHandler();
    
    @Override
    public void doFilterInternal(HttpServletRequest req, HttpServletResponse res,FilterChain chain) throws IOException, ServletException {
    
        //logger.info("Captcha verifier filter");
        boolean captchaPassed=captchaCaptureFilter.getIscaptchaPassed();
        String captchaResponse=captchaCaptureFilter.getCaptchaResponse();
        //logger.info("captcha captured :"+captchaResponse+" validation result of captcha : " +captchaPassed);
    
        if(captchaResponse!=null)
        {
            if(captchaPassed)
            {
                logger.info("Captcha is valid!");
            }
            else
            {
                logger.info("Captcha is invalid!");
                failureHandler.setDefaultFailureUrl(failureUrl);
                failureHandler.onAuthenticationFailure(req, res, new BadCredentialsException("Captcha invalid!"));
            }
            resetCaptchaFields();   
        }
    
        chain.doFilter(req, res);           
    }
    
    /** 
     * Reset Captcha fields
     */
    public void resetCaptchaFields() {
        captchaCaptureFilter.setCaptchaResponse(null);
        captchaCaptureFilter.setIscaptchaPassed(false);;
    }
    
  • 在security-context.xml中更改以下内容
  • 安全性:自定义筛选器ref=“captchapturefilter”before=“FIRST”

    安全性:自定义筛选器ref=“captchavifierfilter”after=“FORM\u LOGIN\u filter”


    我在验证captcha的所有过滤器之前添加captchaCaptureFilter。验证结果在用户名和密码AuthFilter之后使用,即表单\u登录\u过滤器

    您能告诉我,验证码验证发生在AuthenticationProvider的确切位置吗?
    @Override
    public void doFilterInternal(HttpServletRequest req, HttpServletResponse res,FilterChain chain) throws IOException, ServletException {
    
        logger.info("Captcha capture filter");
    
        String captcha_Response=req.getParameter("jcaptcha");
        logger.info("response captcha captured : " +captcha_Response);
    
        if(captcha_Response!=null)
        {
            iscaptchaPassed = SimpleImageCaptchaServlet.validateResponse(req, req.getParameter("jcaptcha"));
            captchaResponse=captcha_Response;
            logger.info("isCaptchaPassed value is "+iscaptchaPassed);
        }
    
        // Proceed with the remaining filters
        chain.doFilter(req, res);
    }
    
    protected Logger logger = LoggerFactory.getLogger(Filter.class);
    
    private CaptchaCaptureFilter captchaCaptureFilter;
    
    private String failureUrl;
    
    //getters and setters**strong text**
    
    private SimpleUrlAuthenticationFailureHandler failureHandler = new SimpleUrlAuthenticationFailureHandler();
    
    @Override
    public void doFilterInternal(HttpServletRequest req, HttpServletResponse res,FilterChain chain) throws IOException, ServletException {
    
        //logger.info("Captcha verifier filter");
        boolean captchaPassed=captchaCaptureFilter.getIscaptchaPassed();
        String captchaResponse=captchaCaptureFilter.getCaptchaResponse();
        //logger.info("captcha captured :"+captchaResponse+" validation result of captcha : " +captchaPassed);
    
        if(captchaResponse!=null)
        {
            if(captchaPassed)
            {
                logger.info("Captcha is valid!");
            }
            else
            {
                logger.info("Captcha is invalid!");
                failureHandler.setDefaultFailureUrl(failureUrl);
                failureHandler.onAuthenticationFailure(req, res, new BadCredentialsException("Captcha invalid!"));
            }
            resetCaptchaFields();   
        }
    
        chain.doFilter(req, res);           
    }
    
    /** 
     * Reset Captcha fields
     */
    public void resetCaptchaFields() {
        captchaCaptureFilter.setCaptchaResponse(null);
        captchaCaptureFilter.setIscaptchaPassed(false);;
    }