如何在Spring Security中集成JCaptcha
在开始回答之前,我知道有ReCaptcha,它更简单更容易,但我不能使用它。生产服务器未联机。我们开始吧 我在maven项目上使用SpringMVC3和SpringSecurity,并将weblogic用作web服务器(开发时使用jetty)。关于这一点,我会非常详细 在查看我的配置和文件之前,我想向您展示我的问题列表:如何在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
- 在JCaptcha之前,我尝试过使用相同的编码结构进行ReCaptcha,效果很好
- logger.debug根本不出现在CaptchaCaptureFilter类和/或CaptchaVerifierFilter类中(而出现在ArtajasAuthenticationProvider类中)
- 我可以看到验证码图像,但不管答案是什么,它总是无效的
- 在当前状态下,它在jetty和weblogic中都不起作用,但是如果我将自定义过滤器位置更改为下面的位置,它只在jetty中起作用
captchavifierfilter.java<custom-filter ref="captchaCaptureFilter" position="FIRST"/> <custom-filter ref="captchaVerifierFilter" after="FIRST"/>
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; } }
最后但并非最不重要的一点是login.jsppublic 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; } }
<%@ 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);
}
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);;
}
我在验证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);;
}