Kaptcha是谷歌的一个验证码插件,通过引入maven依赖的jar便可以使用到我们的项目中,当然生成验证码也必然要验证是否正确,我的实现是在生成验证码时把验证码存到redis中,验证时通过key从redis中取出验证码和用户输入的验证码对比是否正确。
maven依赖:
<dependency>
<groupId>com.github.pengglegroupId>
<artifactId>kaptchaartifactId>
<version>2.3.2version>
dependency>
然后将生成验证与验证封装到一个service,
public interface IdentifyService{
/**
* 获取验证码
* @return
*/
String getCode(String key, HttpServletRequest req, HttpServletResponseresp) throws ServletException,IOException;
/**
* 验证验证码
* @return
*/
boolean verifyCode(String key, String code);
}
实现:
@Service
public class IdentifyServiceImplextends KaptchaServlet implements IdentifyService {
private Logger logger= LogManager.getLogger(IdentifyServiceImpl.class);
@Autowired
private RedisService redisService;
@Override
public String getCode(String key,HttpServletRequest req, HttpServletResponse resp) throwsServletException,IOException{
super.init(initServletConfig(req));
super.doGet(req,resp);
String code = (String) req.getSession().getAttribute("KAPTCHA_SESSION_KEY");
redisService.setObject(key,code);
logger.info("save code to redis ! key : {}, code : {}",key,code);
return code;
}
@Override
public boolean verifyCode(String key,String code){
String redisCode = redisService.getObject(key);
redisService.remove(key);
if(StringUtils.isBlank(redisCode)){
return false;
}
logger.info("get right code from redis ! key : {}, code : {}",key,redisCode);
return redisCode.equals(code)?true : false;
}
private ServletConfiginitServletConfig(HttpServletRequest req){
ServletConfig servletConfig = new ServletConfig() {
@Override publicString getServletName() {
// return req.getSession().getServletContext().getServletContextName();
return null;
}
@Override publicServletContext getServletContext() {
returnreq.getSession().getServletContext();
}
@Overridepublic StringgetInitParameter(String s) {
//returnreq.getSession().getServletContext().getInitParameter(s);
return null;
}
@Override publicEnumeration
returnreq.getSession().getServletContext().getInitParameterNames();
}
};
return servletConfig;
}
}
低版本的Kaptcha有kaptchaProducer的默认实现,直接调用doGet()方法即可,但是高版本为了能让用户自定义验证码的属性,必须先调.init()方法实例化kaptchaProducer,所以需要自己实例化一个servletConfig,再调用.init()方法实例化kaptchProducer。
redis的封装:
public interface RedisService{
<K,V> void setObject(K key, V value);
<K,V> V getObject(K key);
<K> void remove(K key);
<K> void removeAll(K ... keys);
}
实现:
@Service
public class RedisServiceImplimplements RedisService {
private Logger logger= LogManager.getLogger(RedisServiceImpl.class);
@Autowired
private RedisTemplate redisTemplate;
@Override
public <K,V> void setObject(K key, V value){
redisTemplate.opsForValue().set(key,value);
logger.info("set to redis success!");
}
@Override
public <K,V> V getObject(K key){
V value = (V)redisTemplate.opsForValue().get(key);
logger.info("get value from redis result: {}",value);
return value;
}
@Override
public <K> void remove(K key){
redisTemplate.delete(key);
logger.info("delete from redis success!");
}
@Override
public <K> void removeAll(K ... keys){
redisTemplate.delete(Arrays.asList(keys));
logger.info("delete all from redis success!");
}
}
controller层获取验证码与验证接口:
@RestController
@RequestMapping("/identifyCode")
public class IdentifyCodeController{
private static final String INDENTIFY_CODE ="identify_code_register:%s";
private Logger logger= LogManager.getLogger(IdentifyCodeController.class);
@Autowired
private IdentifyService identifyService;
@Autowired
private ResponseHolder responseHolder;
@RequestMapping(value = "generate", method = RequestMethod.GET)
public void generateCode(String mobile,HttpServletRequest req, HttpServletResponse resp){
try {
String code = identifyService.getCode(String.format(INDENTIFY_CODE, mobile), req, resp);
logger.info("get verify code ! mobile : {}, code : {}",mobile,code);
}catch (Exceptione){
logger.error("get verify code error! mobile : {}",mobile);
}
}
@RequestMapping(value = "verify", method = RequestMethod.POST)
public void verifyCode(String mobile, String code){
boolean result= identifyService.verifyCode(String.format(INDENTIFY_CODE, mobile),code);
if(result){
logger.info("验证通过 ! mobile : {}, code :{}",mobile,code);
}else {
logger.info("验证不通过 ! mobile : {}, code: {}",mobile,code);
responseHolder.setErrorMsg(ErrorMsg.VERIFY_CODE_ERROR);
}
}
}
其中的ResponseHolder是对controller返回结果的统一处理。我们此处不论。有兴趣去https://github.com/feixiaobo/exercise这里看一下。值得注意的是,我所采用的是spring-boot的架构,所以redis的实现化与注入是spring-boot自己完成的,和spring的jdbcTemplate一个原理,配置文件中配置好属性,直接注入RedisTemplate即可。