package com.app.mvc.captcha;
import com.app.mvc.acl.enums.Status;
import com.app.mvc.common.ThreadPool;
import com.app.mvc.config.GlobalConfig;
import com.app.mvc.config.GlobalConfigKey;
import com.google.common.base.Preconditions;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Date;
/**
* Created by jimin on 16/3/9.
*/
@Slf4j
@Service
public class CaptchaService {
@Resource
private CaptchaCodeDao captchaCodeDao;
public void saveCaptchaCode(String code, String sessionId) {
Preconditions.checkNotNull(code, "数据非法");
Preconditions.checkArgument(canGenerate(sessionId), "请求次数过于频繁,请稍后重试");
Date expireTime = DateUtils.addMinutes(new Date(), GlobalConfig.getIntValue(GlobalConfigKey.CAPTCHA_CODE_INVALID_MINUTES, 5));
CaptchaCode captchaCode = CaptchaCode.builder().code(code).sessionId(sessionId).expireTime(expireTime).build();
captchaCodeDao.save(captchaCode);
}
public boolean validCaptchaCode(final String code, final String sessionId) {
Preconditions.checkNotNull(code);
Preconditions.checkNotNull(sessionId);
CaptchaCode captchaCode = captchaCodeDao.findLastBySessionId(sessionId);
if (captchaCode == null || captchaCode.getExpireTime().getTime() < System.currentTimeMillis() || captchaCode.getStatus() != Status.AVAILABLE
.getCode()) {
return false;
}
if (captchaCode.getCode().equalsIgnoreCase(code)) {
// 一旦验证码验证通过,则将其置为不可用状态,之后不再允许被使用
// 如果后面需要使用,则须生成新的验证码
asyncInvalidCaptchaCode(code, sessionId);
return true;
}
return false;
}
/**
* 检测一段时间内该session生成验证码的数量是否超出正常范围
*/
private boolean canGenerate(String sessionId) {
Preconditions.checkNotNull(sessionId, "数据非法");
Date targetDate = DateUtils.addMinutes(new Date(), -1);
int maxTimes = GlobalConfig.getIntValue(GlobalConfigKey.CAPTCHA_CODE_ONE_MINUTE_MAX, 2);
return captchaCodeDao.countBySessionIdAndCreateTime(sessionId, targetDate) < maxTimes;
}
private void asyncInvalidCaptchaCode(final String code, final String sessionId) {
ThreadPool.execute(new Runnable() {
@Override
public void run() {
try {
captchaCodeDao.invalidCaptchaCode(sessionId, code);
} catch (Throwable e) {
log.error("invalid captcha code error, code: {}, sessionId: {}", code, sessionId, e);
}
}
});
}
public void asyncFailTry(final String sessionId) {
ThreadPool.execute(new Runnable() {
@Override
public void run() {
try {
failTry(sessionId);
} catch (Throwable e) {
log.error("update captcha code tryTimes error, sessionId: {}", sessionId, e);
}
}
});
}
private void failTry(String sessionId) {
if (StringUtils.isBlank(sessionId)) {
return;
}
CaptchaCode captchaCode = captchaCodeDao.findLastBySessionId(sessionId);
if (captchaCode == null || captchaCode.getExpireTime().getTime() < System.currentTimeMillis() || captchaCode.getStatus() != Status.AVAILABLE
.getCode()) {
return;
}
captchaCodeDao.incrTryTimes(captchaCode.getId());
}
}