The repository for JCaptcha is this one:

<repository>
<id>sourceforge-releases</id>
<name>Sourceforge Releases</name>
<url>https://oss.sonatype.org/content/repositories/sourceforge-releases</url>
</repository> <dependency>
<groupId>com.octo.captcha</groupId>
<artifactId>jcaptcha-integration-simple-servlet</artifactId>
<version>2.0-alpha-1</version>
</dependency>

Here are some configuration I made in .xml files:

web.xml

<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/applicationContext.xml
/WEB-INF/spring/spring-security.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
</listener> <filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter> <filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>FORWARD</dispatcher>
<dispatcher>REQUEST</dispatcher>
</filter-mapping> <servlet>
<servlet-name>jcaptcha</servlet-name>
<servlet-class>com.octo.captcha.module.servlet.image.SimpleImageCaptchaServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>jcaptcha</servlet-name>
<url-pattern>/jcaptcha.jpg</url-pattern>
</servlet-mapping>

spring-security.xml

<http auto-config="true" use-expressions="true">
<intercept-url pattern="/resources/**" access="permitAll()" />
<intercept-url pattern="/jcaptcha.jpg" access="permitAll()" />
<intercept-url pattern="/**" access="isAuthenticated()" /> <form-login login-page="/session/login/" default-target-url="/"
authentication-failure-url="/session/loginfailed/" />
<logout logout-success-url="/session/logout/" />
<access-denied-handler error-page="/session/403/" /> <!--JCaptcha Filtering-->
<custom-filter ref="captchaCaptureFilter" before="FORM_LOGIN_FILTER"/>
<!-- REMOVED custom-filter ref="captchaVerifierFilter" after="FORM_LOGIN_FILTER"/-->
<anonymous />
</http> <!-- For capturing CAPTCHA fields -->
<beans:bean id="captchaCaptureFilter" class="com.util.CaptchaCaptureFilter" /> <!-- For verifying CAPTCHA fields -->
<!-- Private key is assigned by the JCaptcha service -->
<!-- REMOVED beans:bean id="captchaVerifierFilter" class="com.util.CaptchaVerifierFilter"
p:failureUrl="/session/loginfailed/"
p:captchaCaptureFilter-ref="captchaCaptureFilter"/--> <beans:property name="sessionAuthenticationStrategy" ref="sas"/>
<beans:property name="authenticationManager" ref="authenticationManager" />
<beans:property name="allowSessionCreation" value="true" />
</beans:bean> <beans:bean id="sas" class="org.springframework.security.web.authentication.session.ConcurrentSessionControlStrategy">
<beans:constructor-arg name="sessionRegistry" ref="sessionRegistry"/>
<beans:property name="maximumSessions" value="1" />
</beans:bean> <beans:bean id="sessionRegistry" class="org.springframework.security.core.session.SessionRegistryImpl" /> <beans:bean id="userService" class="com.service.mybatis.UserManager" /> <beans:bean id="customAuthenticationProvider" class="com.util.MyAuthenticationProvider" p:captchaCaptureFilter-ref="captchaCaptureFilter" />
<authentication-manager alias="authenticationManager">
<authentication-provider ref="customAuthenticationProvider" />
</authentication-manager> <beans:bean id="accessDeniedHandler" class="com.util.ThouShaltNoPass">
<beans:property name="accessDeniedURL" value="/session/403/" />
</beans:bean>

And these are the java classes:

MyAuthenticationProvider.java

public class MyAuthenticationProvider implements AuthenticationProvider {

@Autowired
private UserService userService;
private Logger logger = LoggerFactory.getLogger(ArtajasaAuthenticationProvider.class);
private CaptchaCaptureFilter captchaCaptureFilter; @Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String username = String.valueOf(authentication.getPrincipal());
String password = String.valueOf(authentication.getCredentials());
logger.debug("Checking authentication for user {}", username);
logger.debug("userResponse: {}", captchaCaptureFilter.getUserCaptchaResponse());
if (StringUtils.isBlank(username)
|| StringUtils.isBlank(password)) {
throw new BadCredentialsException("No Username and/or Password Provided.");
}
else if(StringUtils.isBlank(captchaCaptureFilter.getUserCaptchaResponse())) {
throw new BadCredentialsException("Captcha Response is Empty");
}
else {
// 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 valid!");
resetCaptchaFields(); Pengguna user = userService.select(username);
if (user == null) {
throw new BadCredentialsException("Invalid Username and/or Password.");
}
if (user.getPassword().equals(new PasswordUtil().generateHash(password, user.getSalt()))) {
List<GrantedAuthority> authorityList = (List<GrantedAuthority>) userService.getAuthorities(user);
return new UsernamePasswordAuthenticationToken(username, password, authorityList);
}
else {
throw new BadCredentialsException("Invalid Username and/or Password.");
}
}
else {
logger.debug("Captcha is invalid!");
resetCaptchaFields(); throw new BadCredentialsException("Invalid Captcha.");
}
}
} @Override
public boolean supports(Class<?> authentication) {
return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
} /**
* Reset Captcha fields
*/
public void resetCaptchaFields() {
captchaCaptureFilter.setUserCaptchaResponse(null);
} public CaptchaCaptureFilter getCaptchaCaptureFilter() {
return captchaCaptureFilter;
} public void setCaptchaCaptureFilter(CaptchaCaptureFilter captchaCaptureFilter) {
this.captchaCaptureFilter = captchaCaptureFilter;
}
}

CaptchaCaptureFilter.java

public class CaptchaCaptureFilter extends OncePerRequestFilter {

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

Last but not least, 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>

done!

How to Integrate JCaptcha in Spring Security的更多相关文章

  1. Spring Security(三十六):12. Spring MVC Test Integration

    Spring Security provides comprehensive integration with Spring MVC Test Spring Security提供与Spring MVC ...

  2. Spring Security(二十七):Part II. Architecture and Implementation

    Once you are familiar with setting up and running some namespace-configuration based applications, y ...

  3. Spring Security(十二):5. Java Configuration

    General support for Java Configuration was added to Spring Framework in Spring 3.1. Since Spring Sec ...

  4. Spring Security(十一):4. Samples and Guides (Start Here)

    If you are looking to get started with Spring Security, the best place to start is our Sample Applic ...

  5. Spring Security(四):2.1 Introduction What is Spring Security?

    Spring Security provides comprehensive security services for Java EE-based enterprise software appli ...

  6. spring security 学习文档

    web service Prepared by:   Sea                                                                       ...

  7. spring-security-4 (2)spring security 基于Java配置的搭建

    一.spring security的模块 搭建spring security首先我们要导入必须的jar,即maven的依赖.spring security按模块划分,一个模块对应一个jar. spri ...

  8. Spring security 3.1 +JSF 2.0 . problem with annotating methods in ManagedBeans?

    Hy .What i am trying to do is to integrate Spring security with a Jsf+spring IOC +hibernate applicat ...

  9. Spring Security Java Config Preview--官方

    原文地址:[1]https://spring.io/blog/2013/07/02/spring-security-java-config-preview-introduction/ [2]https ...

随机推荐

  1. UVALive-3415 Guardian of Decency (最大独立集)

    题目大意:一个老师要带一些学生去春游,但是要带的学生中任意两个人都满足下面四个条件中的至少一个:1.性别相同:2.身高差大与40公分:3.最喜欢的音乐类型不同:4.最喜欢的体育运动相同.问老师最多能带 ...

  2. IE8下的typeof(console.log)为"object"的BUG

    今天发现IE8在开启过控制台后,console.log虽然可用,也是确实是一个函数,但是对其执行typeof操作返回的确是"object" 原生IE8:

  3. 『转』三星推出Android智能手表Galaxy Gear

    苹果定下来本月10日召开新品发布会,而它的竞争对手三星却抢先一步.今天凌晨,三星在德国柏林一口气发布了三款重量级产品.三星智能手表Galaxy Gear最引人关注,其将于9月25日陆续在全球上市,售价 ...

  4. STL标准库-容器-unordered_set

    技术在于交流.沟通,本文为博主原创文章转载请注明出处并保持作品的完整性 unordered_set与与unordered_map相似,这次主要介绍unordered_set unordered_set ...

  5. vue music 歌单组件

    在data里面定义 discList: [] methods: { _getRecommend() { getRecommend().then((res) => { if(res.code == ...

  6. TypeScript学习笔记(三) - 方法

    本篇将介绍在TypeScript里如何定义和使用方法. 一.方法标准声明和使用 // 方法声明 function func(x: number, y: number): number { return ...

  7. 使用promise方式来获取网络数据

    获取网络数据 let data = []; new Promise(function(resolve,reject){ axios.post('api.php').then(function(resp ...

  8. python3的eval和exec的区别与联系

    eval: 可以把字符串里的字符转换为可执行代码,但只支持一行字符.可以返回执行后得到的值.如下: f = "3+6+9+8"s = eval(f)print(s)输出: &quo ...

  9. js setInterval每隔一段时间执行一次

    js setInterval每隔一段时间执行一次setInterval() 方法可按照指定的周期(以毫秒计)来调用函数或计算表达式.setInterval() 方法会不停地调用函数,直到 clearI ...

  10. 字符串循环右移N位

    给一个长度为n的字符串,把这个字符串循环右移N位(0<N<n),要求只用O(1)的额外空间和O(N)时间,有些什么方法 一开始想到的是先保存temp=s[0],在左起第N个移到s[0]的位 ...