spring mvc/security 应用程序中的验证码
Captcha in spring mvc/security application
我需要为 spring 应用程序实施验证码。
我正在研究不同的选项,虽然许多人推荐 reCaptcha,但我们很可能无法使用它,因为该应用程序将是内部应用程序(无法访问互联网)。
让我信服的选项是 BotDetect(因为 SimpleCaptcha 没有指定任何关于 Java 1.7 的支持)
我们将身份验证留给 spring 安全性,因为我们没有带 @RequestMapping("/login") 的控制器,我决定通过拦截器验证验证码,覆盖 preHandle 方法。
我的问题是由于请求中未包含的某些原因,我无法从拦截器中检索验证码。
我的代码基于文档 BotDetect (https://captcha.com/doc/java/howto/springmvc-captcha.html)
知道为什么不起作用吗?或者,如果有任何其他替代方案可以使用 spring 安全性来实现验证码
这是我的 jsp:
<form action="/businessPortal/login" method="post" role="form">
<div class="form-group">
<label for="userName">
<spring:message code="IntroPage.UserName" />:
</label>
<input type="text" id="userName" name="j_username" class="form-control" tabindex="1">
</div>
<p class="divider"></p>
<div class="form-group">
<label for="password">
<spring:message code="IntroPage.Password" />:
</label>
<input type="password" id="password" name="j_password" class="form-control" tabindex="2">
</div>
<p class="divider"></p>
<div class="form-group">
<botDetect:captcha id="basicExampleCaptcha"/>
<div class="validationDiv">
<input id="captchaCodeTextBox" type="text" name="captchaCodeTextBox" value="${basicExample.captchaCodeTextBox}"/>
</div>
</div>
<input type="submit" class="btn btn-primary btn-lg" value="Iniciar Sesión" />
</form>
这是我的 spring 安全配置:
<sec:http use-expressions="true" auto-config="false">
...
<sec:form-login login-page="/login"
authentication-failure-url="/accessDenied"
authentication-success-handler-ref="authSuccessHandler"
authentication-failure-handler-ref="authFailureHandler"
login-processing-url="/login" />
<sec:access-denied-handler error-page="/accessDenied" />
<sec:logout />
</sec:http>
拦截器配置:
<mvc:interceptors>
<bean id="validateCaptchaInterceptor" class="com.project.backend.security.captcha.ValidateCaptchaInterceptor">
</bean>
</mvc:interceptors>
这是拦截器代码:
public class ValidateCaptchaInterceptor extends HandlerInterceptorAdapter{
private static final Logger logger = Logger.getLogger(ValidateCaptchaInterceptor.class);
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object command){
boolean isHuman = true;
if(request.getRequestURL().toString().indexOf("login") != -1){
BasicExample basicExample = (BasicExample)command;
// validate the Captcha to check we're not dealing with a bot
Captcha captcha = Captcha.load(request, "basicExampleCaptcha");
isHuman = captcha.validate(request,basicExample.getCaptchaCodeTextBox());
}
return isHuman;
}
}
已解决
我终于用过滤器解决了(不是拦截器)
这是我的过滤器和声明(我想在 FORM_LOGIN_FILTER 之前执行此过滤器)
<sec:http use-expressions="true" auto-config="false">
...
<sec:custom-filter ref="captchaFilter" before="FORM_LOGIN_FILTER"/>
...
</sec:http>
<bean id="captchaFilter" class="path.to.my.filter.CaptchaFilter" p:postOnly="false">
<property name="authenticationManager" ref="authenticationManager" />
<property name="authenticationFailureHandler" ref="authFailureHandler" />
<property name="authenticationSuccessHandler" ref="authSuccessHandler" />
<property name="restTemplate" ref="commonRestTemplate" />
</bean>
这是我的过滤器代码:
public class CaptchaFilter extends UsernamePasswordAuthenticationFilter {
@Autowired
private RestTemplate restTemplate;
private static final String POST = "POST";
private static final Logger LOG = Logger.getLogger(UsernamePasswordAuthenticationFilter.class);
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
...
}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
final HttpServletRequest request = (HttpServletRequest) req;
final HttpServletResponse response = (HttpServletResponse) res;
if(request.getRequestURI().indexOf("login") != -1 && request.getMethod().equals(POST) &&
LoginAttemptsSingleton.getInstance().getLoginAttepmts().containsKey(ipAddress) &&
LoginAttemptsSingleton.getInstance().getLoginAttepmts().get(ipAddress) > 3){
//Captcha validation here
}else{
//No captcha validation, so keep going throug next filter in chain
chain.doFilter(request, response);
}
}
}
我需要为 spring 应用程序实施验证码。
我正在研究不同的选项,虽然许多人推荐 reCaptcha,但我们很可能无法使用它,因为该应用程序将是内部应用程序(无法访问互联网)。
让我信服的选项是 BotDetect(因为 SimpleCaptcha 没有指定任何关于 Java 1.7 的支持)
我们将身份验证留给 spring 安全性,因为我们没有带 @RequestMapping("/login") 的控制器,我决定通过拦截器验证验证码,覆盖 preHandle 方法。
我的问题是由于请求中未包含的某些原因,我无法从拦截器中检索验证码。
我的代码基于文档 BotDetect (https://captcha.com/doc/java/howto/springmvc-captcha.html)
知道为什么不起作用吗?或者,如果有任何其他替代方案可以使用 spring 安全性来实现验证码
这是我的 jsp:
<form action="/businessPortal/login" method="post" role="form">
<div class="form-group">
<label for="userName">
<spring:message code="IntroPage.UserName" />:
</label>
<input type="text" id="userName" name="j_username" class="form-control" tabindex="1">
</div>
<p class="divider"></p>
<div class="form-group">
<label for="password">
<spring:message code="IntroPage.Password" />:
</label>
<input type="password" id="password" name="j_password" class="form-control" tabindex="2">
</div>
<p class="divider"></p>
<div class="form-group">
<botDetect:captcha id="basicExampleCaptcha"/>
<div class="validationDiv">
<input id="captchaCodeTextBox" type="text" name="captchaCodeTextBox" value="${basicExample.captchaCodeTextBox}"/>
</div>
</div>
<input type="submit" class="btn btn-primary btn-lg" value="Iniciar Sesión" />
</form>
这是我的 spring 安全配置:
<sec:http use-expressions="true" auto-config="false">
...
<sec:form-login login-page="/login"
authentication-failure-url="/accessDenied"
authentication-success-handler-ref="authSuccessHandler"
authentication-failure-handler-ref="authFailureHandler"
login-processing-url="/login" />
<sec:access-denied-handler error-page="/accessDenied" />
<sec:logout />
</sec:http>
拦截器配置:
<mvc:interceptors>
<bean id="validateCaptchaInterceptor" class="com.project.backend.security.captcha.ValidateCaptchaInterceptor">
</bean>
</mvc:interceptors>
这是拦截器代码:
public class ValidateCaptchaInterceptor extends HandlerInterceptorAdapter{
private static final Logger logger = Logger.getLogger(ValidateCaptchaInterceptor.class);
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object command){
boolean isHuman = true;
if(request.getRequestURL().toString().indexOf("login") != -1){
BasicExample basicExample = (BasicExample)command;
// validate the Captcha to check we're not dealing with a bot
Captcha captcha = Captcha.load(request, "basicExampleCaptcha");
isHuman = captcha.validate(request,basicExample.getCaptchaCodeTextBox());
}
return isHuman;
}
}
已解决
我终于用过滤器解决了(不是拦截器)
这是我的过滤器和声明(我想在 FORM_LOGIN_FILTER 之前执行此过滤器)
<sec:http use-expressions="true" auto-config="false">
...
<sec:custom-filter ref="captchaFilter" before="FORM_LOGIN_FILTER"/>
...
</sec:http>
<bean id="captchaFilter" class="path.to.my.filter.CaptchaFilter" p:postOnly="false">
<property name="authenticationManager" ref="authenticationManager" />
<property name="authenticationFailureHandler" ref="authFailureHandler" />
<property name="authenticationSuccessHandler" ref="authSuccessHandler" />
<property name="restTemplate" ref="commonRestTemplate" />
</bean>
这是我的过滤器代码:
public class CaptchaFilter extends UsernamePasswordAuthenticationFilter {
@Autowired
private RestTemplate restTemplate;
private static final String POST = "POST";
private static final Logger LOG = Logger.getLogger(UsernamePasswordAuthenticationFilter.class);
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
...
}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
final HttpServletRequest request = (HttpServletRequest) req;
final HttpServletResponse response = (HttpServletResponse) res;
if(request.getRequestURI().indexOf("login") != -1 && request.getMethod().equals(POST) &&
LoginAttemptsSingleton.getInstance().getLoginAttepmts().containsKey(ipAddress) &&
LoginAttemptsSingleton.getInstance().getLoginAttepmts().get(ipAddress) > 3){
//Captcha validation here
}else{
//No captcha validation, so keep going throug next filter in chain
chain.doFilter(request, response);
}
}
}