接口信息
生成验证码图片
校验验证码图片
配置图片生成
使用开源的图片生成工具 Kaptcha,并进行自定义的配置
@Configuration public class KaptchaConfig {
@Bean public DefaultKaptcha producer() { Properties properties = new Properties(); properties.put("kaptcha.border", "no"); properties.put("kaptcha.textproducer.font.color", "black"); properties.put("kaptcha.textproducer.char.space", "10"); properties.put("kaptcha.textproducer.char.length", "4"); properties.put("kaptcha.image.height", "34"); properties.put("kaptcha.image.width", "138"); properties.put("kaptcha.textproducer.font.size", "25");
properties.put("kaptcha.noise.impl", "com.google.code.kaptcha.impl.NoNoise"); Config config = new Config(properties); DefaultKaptcha defaultKaptcha = new DefaultKaptcha(); defaultKaptcha.setConfig(config); return defaultKaptcha; } }
|
Model实体类
在com.swx.checkcode.model
包下创建下面两个实体类:
验证码参数类
CheckCodeParamsDTO
@Data public class CheckCodeParamsDTO {
private String checkCodeType;
private String param1; private String param2; private String param3; }
|
验证码结果类
CheckCodeResultVO
@Data public class CheckCodeResultVO {
private String key;
private String aliasing; }
|
Service方法
接口定义
在com.swx.checkcode.service
包下创建下面接口:
public interface CheckCodeService {
CheckCodeResultVO generate(CheckCodeParamsDTO dto);
public boolean verify(String key, String code);
public interface CheckCodeGenerator {
String generate(int length); }
public interface KeyGenerator {
String generate(String prefix); }
public interface CheckCodeStore {
void set(String key, String value, Integer expire);
String get(String key);
void remove(String key); } }
|
使用抽象类实现该接口,提供基础功能
AbstractCheckCodeService
@Slf4j public abstract class AbstractCheckCodeService implements CheckCodeService {
protected CheckCodeGenerator checkCodeGenerator; protected KeyGenerator keyGenerator; protected CheckCodeStore checkCodeStore;
public abstract void setCheckCodeGenerator(CheckCodeGenerator checkCodeGenerator); public abstract void setKeyGenerator(KeyGenerator keyGenerator); public abstract void setCheckCodeStore(CheckCodeStore CheckCodeStore);
public GenerateResult generate(CheckCodeParamsDTO dto, Integer codeLength, String keyPrefix, Integer expire) { String code = checkCodeGenerator.generate(codeLength); String key = keyGenerator.generate(keyPrefix);
checkCodeStore.set(key, code, expire); return new GenerateResult(key, code); }
public boolean verify(String key, String code) { if (StringUtils.isBlank(key) || StringUtils.isBlank(code)) { return false; } String code_l = checkCodeStore.get(key); if (code_l == null) { return false; } boolean result = code_l.equalsIgnoreCase(code); if (result) { checkCodeStore.remove(key); } return result; }
@Data protected static class GenerateResult { String key; String code;
GenerateResult() {
}
GenerateResult(String key, String code) { this.key = key; this.code = code; } }
public abstract CheckCodeResultVO generate(CheckCodeParamsDTO checkCodeParamsDto); }
|
实现缓存接口
使用策略模式,实现不同的缓存方案。
内存缓存
将验证码数据存放在内存中
MemoryCheckCodeStore@Component("MemoryCheckCodeStore") public class MemoryCheckCodeStore implements CheckCodeService.CheckCodeStore {
Map<String, String> map = new HashMap<String, String>();
@Override public void set(String key, String value, Integer expire) { map.put(key, value); }
@Override public String get(String key) { return map.get(key); }
@Override public void remove(String key) { map.remove(key); } }
|
Redis缓存
使用redis存储验证码,可以设置过期时间
RedisCheckCodeStore
@Component("RedisCheckCodeStore") public class RedisCheckCodeStore implements CheckCodeService.CheckCodeStore {
private final StringRedisTemplate redisTemplate;
public RedisCheckCodeStore(StringRedisTemplate redisTemplate) { this.redisTemplate = redisTemplate; }
@Override public void set(String key, String value, Integer expire) { redisTemplate.opsForValue().set(key, value, expire, TimeUnit.SECONDS); }
@Override public String get(String key) { return redisTemplate.opsForValue().get(key); }
@Override public void remove(String key) { redisTemplate.delete(key); } }
|
实现生成验证码
实现 CheckCodeService.CheckCodeGenerator 接口
NumberLetterCheckCodeGenerator
@Component("NumberLetterCheckCodeGenerator") public class NumberLetterCheckCodeGenerator implements CheckCodeService.CheckCodeGenerator {
@Override public String generate(int length) { String str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; Random random = new Random(); StringBuilder sb = new StringBuilder(); for (int i = 0; i < length; i++) { int number = random.nextInt(36); sb.append(str.charAt(number)); } return sb.toString(); } }
|
实现生成Key接口
实现 CheckCodeService.KeyGenerator 接口
UUIDKeyGenerator
@Component("UUIDKeyGenerator") public class UUIDKeyGenerator implements CheckCodeService.KeyGenerator { @Override public String generate(String prefix) { String uuid = UUID.randomUUID().toString(); return prefix + uuid.replaceAll("-", ""); } }
|
实现图片验证码
继承 AbstractCheckCodeService 抽象类,实现 CheckCodeService 接口。注入指定的实现类,实现生成图片验证码的同时,将生成的key和code缓存至Redis。
PicCheckCodeServiceImpl
@Slf4j @Service("PicCheckCodeService") public class PicCheckCodeServiceImpl extends AbstractCheckCodeService implements CheckCodeService {
private final DefaultKaptcha kaptcha;
public PicCheckCodeServiceImpl(DefaultKaptcha kaptcha) { this.kaptcha = kaptcha; }
@Resource(name="NumberLetterCheckCodeGenerator") @Override public void setCheckCodeGenerator(CheckCodeGenerator checkCodeGenerator) { this.checkCodeGenerator = checkCodeGenerator; }
@Resource(name="UUIDKeyGenerator") @Override public void setKeyGenerator(KeyGenerator keyGenerator) { this.keyGenerator = keyGenerator; }
@Resource(name="RedisCheckCodeStore") @Override public void setCheckCodeStore(CheckCodeStore checkCodeStore) { this.checkCodeStore = checkCodeStore; }
@Override public CheckCodeResultVO generate(CheckCodeParamsDTO dto) { GenerateResult generate = generate(dto, 4, "checkcode:", 60); String key = generate.getKey(); String code = generate.getCode(); String pic = createPic(code); CheckCodeResultVO resultDTO = new CheckCodeResultVO(); resultDTO.setAliasing(pic); resultDTO.setKey(key); return resultDTO; }
private String createPic(String code) { ByteArrayOutputStream outputStream = null; BufferedImage image = kaptcha.createImage(code);
outputStream = new ByteArrayOutputStream(); String imgBase64Encoder = null; try { ImageIO.write(image, "png", outputStream); imgBase64Encoder = "data:image/png;base64," + Base64Utils.encodeToString(outputStream.toByteArray()); } catch (IOException e) { log.error("图片验证码生成错误", e); } finally { try { outputStream.close(); } catch (IOException e) { log.error("流关闭失败", e); } } return imgBase64Encoder; } }
|
Controller服务
主要提供验证码获取和验证功能,其中验证功能将由认证授权微服务远程调用,进行登陆时验证码的验证。
CheckCodeController@Api(value = "验证码服务接口", tags = "验证码服务接口") @RestController public class CheckCodeController {
private final CheckCodeService picCheckCodeService;
public CheckCodeController(CheckCodeService picCheckCodeService) { this.picCheckCodeService = picCheckCodeService; }
@ApiOperation(value="生成验证信息", notes="生成验证信息") @PostMapping(value = "/pic") public CheckCodeResultVO generatePicCheckCode(CheckCodeParamsDTO dto){ return picCheckCodeService.generate(dto); }
@ApiOperation(value="校验", notes="校验") @ApiImplicitParams({ @ApiImplicitParam(name = "name", value = "业务名称", required = true, dataType = "String", paramType="query"), @ApiImplicitParam(name = "key", value = "验证key", required = true, dataType = "String", paramType="query"), @ApiImplicitParam(name = "code", value = "验证码", required = true, dataType = "String", paramType="query") }) @PostMapping(value = "/verify") public Boolean verify(String key, String code){ return picCheckCodeService.verify(key, code); } }
|