提交 afba8405 编写于 作者: dong.an's avatar dong.an

图形验证码

上级 13fb0826
流水线 #13065 已失败 于阶段
...@@ -113,6 +113,12 @@ ...@@ -113,6 +113,12 @@
<artifactId>pica-cloud-account-common</artifactId> <artifactId>pica-cloud-account-common</artifactId>
<version>1.0.0</version> <version>1.0.0</version>
</dependency> </dependency>
<dependency>
<groupId>net.spy</groupId>
<artifactId>spymemcached</artifactId>
<version>2.12.3</version>
</dependency>
</dependencies> </dependencies>
<dependencyManagement> <dependencyManagement>
......
...@@ -34,7 +34,6 @@ public class CaptchaController { ...@@ -34,7 +34,6 @@ public class CaptchaController {
return PicaResponse.toResponse(captchaToken); return PicaResponse.toResponse(captchaToken);
} }
/*
@ApiOperation("校验图形验证码") @ApiOperation("校验图形验证码")
@GetMapping("/acknowledge") @GetMapping("/acknowledge")
public PicaResponse<Boolean> acknowledge(@ApiParam("token") @RequestParam("token") String token, public PicaResponse<Boolean> acknowledge(@ApiParam("token") @RequestParam("token") String token,
...@@ -42,6 +41,5 @@ public class CaptchaController { ...@@ -42,6 +41,5 @@ public class CaptchaController {
boolean valid = captchaService.acknowledge(token, answer); boolean valid = captchaService.acknowledge(token, answer);
return PicaResponse.toResponse(valid); return PicaResponse.toResponse(valid);
} }
*/
} }
package com.pica.cloud.account.account.server.service.impl; package com.pica.cloud.account.account.server.service.impl;
import com.pica.cloud.account.account.server.service.CaptchaService; import com.pica.cloud.account.account.server.service.CaptchaService;
import com.pica.cloud.account.account.server.util.MemcachedClientWrapper;
import com.pica.cloud.account.account.server.util.captcha.CaptchaGenerator; import com.pica.cloud.account.account.server.util.captcha.CaptchaGenerator;
import com.pica.cloud.account.account.server.util.captcha.CaptchaToken; import com.pica.cloud.account.account.server.util.captcha.CaptchaToken;
import com.pica.cloud.foundation.redis.ICacheClient; import com.pica.cloud.foundation.redis.ICacheClient;
...@@ -18,14 +19,11 @@ import java.util.UUID; ...@@ -18,14 +19,11 @@ import java.util.UUID;
public class CaptchaServiceImpl implements CaptchaService { public class CaptchaServiceImpl implements CaptchaService {
private final int size = 5; private final int size = 5;
private final int EXPIRE = 5 * 60; // 5 minutes
private final String CAPTCHA_PREFIX = "captcha-"; private final String CAPTCHA_PREFIX = "captcha-";
@Autowired @Autowired
private CaptchaGenerator agent; private CaptchaGenerator agent;
@Autowired @Autowired
@Qualifier("cacheMigrateClient") MemcachedClientWrapper cache;
private ICacheClient redisClient;
@Override @Override
public CaptchaToken generateToken(int width, int height) { public CaptchaToken generateToken(int width, int height) {
String origin = agent.generateChars(size); String origin = agent.generateChars(size);
...@@ -34,14 +32,14 @@ public class CaptchaServiceImpl implements CaptchaService { ...@@ -34,14 +32,14 @@ public class CaptchaServiceImpl implements CaptchaService {
ret.setBuf(buf); ret.setBuf(buf);
ret.setOrigin(origin); ret.setOrigin(origin);
ret.setToken(DigestUtils.md5Hex(UUID.randomUUID().toString())); ret.setToken(DigestUtils.md5Hex(UUID.randomUUID().toString()));
redisClient.set(CAPTCHA_PREFIX + ret.getToken(), origin, EXPIRE); cache.set(CAPTCHA_PREFIX + ret.getToken(), origin);
return ret; return ret;
} }
@Override @Override
public boolean acknowledge(String token, String answer) { public boolean acknowledge(String token, String answer) {
String origin = redisClient.get(CAPTCHA_PREFIX + token); String origin = cache.get(CAPTCHA_PREFIX + token);
redisClient.del(CAPTCHA_PREFIX + token); cache.remove(CAPTCHA_PREFIX + token);
if (origin != null && answer != null) { if (origin != null && answer != null) {
return origin.compareToIgnoreCase(answer) == 0; return origin.compareToIgnoreCase(answer) == 0;
} }
......
package com.pica.cloud.account.account.server.util;
import net.spy.memcached.AddrUtil;
import net.spy.memcached.ConnectionFactoryBuilder;
import net.spy.memcached.MemcachedClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.io.IOException;
/**
* @author Laurence Cao
*
*/
@Component
public class MemcachedClientWrapper {
private final int EXPIRE = 5 * 60; // 5 minutes
private MemcachedClient cli;
public MemcachedClientWrapper(@Value("${memcached.url}") String url) {
try {
cli = new MemcachedClient(new ConnectionFactoryBuilder().setProtocol(ConnectionFactoryBuilder.Protocol.BINARY).build(), AddrUtil.getAddresses(url));
} catch (IOException e) {
e.printStackTrace();
}
}
public String get(String token) {
return (String)cli.get(token);
}
public void set(String token, String answer) {
cli.set(token, EXPIRE, answer);
}
public void remove(String token) {
cli.delete(token);
}
}
...@@ -3,24 +3,38 @@ package com.pica.cloud.account.account.server.util.captcha; ...@@ -3,24 +3,38 @@ package com.pica.cloud.account.account.server.util.captcha;
import com.google.common.collect.Range; import com.google.common.collect.Range;
import com.google.common.collect.RangeMap; import com.google.common.collect.RangeMap;
import com.google.common.collect.TreeRangeMap; import com.google.common.collect.TreeRangeMap;
import org.springframework.stereotype.Component;
import java.awt.*; import java.awt.*;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
/** /**
* @author Laurence Cao * @author Laurence Cao
* *
*/ */
public abstract class CaptchaGenerator { @Component
public class CaptchaGenerator {
protected RangeMap<Integer, CaptchaContext> ctxs = TreeRangeMap.create(); protected RangeMap<Integer, CaptchaContext> ctxs = TreeRangeMap.create();
protected List<Generator> gens = new ArrayList();
public CaptchaGenerator(boolean showGrid) throws FontFormatException, IOException { class NumberLetterGenerator implements Generator {
@Override
public String generateChars(int size) {
return CaptchaUtil.generateUUIDText(size);
}
}
public CaptchaGenerator() throws FontFormatException, IOException {
int h = 40; int h = 40;
ctxs.put(Range.closed(0, h), new CaptchaContext(h * 4, h, h / 5 * 4, showGrid)); ctxs.put(Range.closedOpen(0, h), new CaptchaContext(h * 4, h, h / 5 * 4, true));
h *= 2; h *= 2;
ctxs.put(Range.closed(h / 2, h), new CaptchaContext(h * 4, h, h / 5 * 4, showGrid)); ctxs.put(Range.closedOpen(h / 2, h), new CaptchaContext(h * 4, h, h / 5 * 4, true));
h *= 2; h *= 2;
ctxs.put(Range.closed(h / 2, Integer.MAX_VALUE), new CaptchaContext(h * 4, h, h / 5 * 4, showGrid)); ctxs.put(Range.closedOpen(h / 2, Integer.MAX_VALUE), new CaptchaContext(h * 4, h, h / 5 * 4, true));
gens.add(new NumberLetterGenerator());
} }
@SuppressWarnings("unused") @SuppressWarnings("unused")
...@@ -32,5 +46,10 @@ public abstract class CaptchaGenerator { ...@@ -32,5 +46,10 @@ public abstract class CaptchaGenerator {
return CaptchaUtil.generateImage(text, ctx); return CaptchaUtil.generateImage(text, ctx);
} }
public abstract String generateChars(int size); public String generateChars(int size) {
int idx = ThreadLocalRandom.current().nextInt(gens.size());
Generator gen = gens.get(idx);
return gen.generateChars(size);
}
} }
...@@ -7,7 +7,10 @@ import javax.imageio.ImageIO; ...@@ -7,7 +7,10 @@ import javax.imageio.ImageIO;
import java.awt.*; import java.awt.*;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.net.URL;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadLocalRandom;
...@@ -40,22 +43,25 @@ public class CaptchaUtil { ...@@ -40,22 +43,25 @@ public class CaptchaUtil {
return ret; return ret;
} }
public static BufferedImage createCaptcha(String src, CaptchaContext ctx) { public static BufferedImage createCaptcha(String src, CaptchaContext ctx) throws IOException{
char[] text = src == null ? new char[0] : src.toCharArray(); char[] text = src == null ? new char[0] : src.toCharArray();
if (text == null || text.length == 0) { if (text == null || text.length == 0) {
throw new IllegalArgumentException("No captcha text given"); throw new IllegalArgumentException("No captcha text given");
} }
BufferedImage image = new BufferedImage(ctx.width, ctx.height, BufferedImage.TYPE_INT_RGB); //BufferedImage image = new BufferedImage(ctx.width, ctx.height, BufferedImage.TYPE_INT_RGB);
String name = (ThreadLocalRandom.current().nextInt(2) + 1) + ".png";
URL url = CaptchaUtil.class.getClassLoader().getResource(name);
BufferedImage image = ImageIO.read(url);
Graphics2D g2d = image.createGraphics(); Graphics2D g2d = image.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setBackground(Color.WHITE); //g2d.setBackground(Color.WHITE);
g2d.setColor(Color.BLACK); g2d.setColor(Color.BLACK);
clearCanvas(g2d, ctx); //clearCanvas(g2d, ctx);
if (ctx.showGrid) { if (ctx.showGrid) {
drawGrid(g2d, ctx); //drawGrid(g2d, ctx);
} }
int charMaxWidth = ctx.width / text.length; int charMaxWidth = ctx.width / text.length;
......
/**
*
*/
package com.pica.cloud.account.account.server.util.captcha;
/**
* @author Laurence Cao
*
*/
public interface Generator {
/**
* generate string by fixed size
*
* @param size
* @return
*/
String generateChars(int size);
}
package com.pica.cloud.account.account.server.util.captcha;
import org.springframework.stereotype.Component;
import java.awt.*;
import java.io.IOException;
/**
* @author Laurence Cao
*
*/
@Component
public class NumberLetterGenerator extends CaptchaGenerator {
public NumberLetterGenerator() throws FontFormatException, IOException {
super(true);
}
@Override
public String generateChars(int size) {
return CaptchaUtil.generateUUIDText(size);
}
}
...@@ -32,4 +32,6 @@ ribbon.ConnectTimeout=60000 ...@@ -32,4 +32,6 @@ ribbon.ConnectTimeout=60000
#------------ Please don't change above configurations ------------ #------------ Please don't change above configurations ------------
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8 spring.jackson.time-zone=GMT+8
\ No newline at end of file
memcached.url=192.168.130.230:11211
\ No newline at end of file
...@@ -32,4 +32,6 @@ ribbon.ConnectTimeout=60000 ...@@ -32,4 +32,6 @@ ribbon.ConnectTimeout=60000
#------------ Please don't change above configurations ------------ #------------ Please don't change above configurations ------------
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8 spring.jackson.time-zone=GMT+8
\ No newline at end of file
memcached.url=192.168.130.230:11211
\ No newline at end of file
...@@ -32,4 +32,6 @@ ribbon.ConnectTimeout=60000 ...@@ -32,4 +32,6 @@ ribbon.ConnectTimeout=60000
#------------ Please don't change above configurations ------------ #------------ Please don't change above configurations ------------
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8 spring.jackson.time-zone=GMT+8
\ No newline at end of file
memcached.url=192.168.130.230:11211
\ No newline at end of file
...@@ -32,4 +32,6 @@ ribbon.ConnectTimeout=60000 ...@@ -32,4 +32,6 @@ ribbon.ConnectTimeout=60000
#------------ Please don't change above configurations ------------ #------------ Please don't change above configurations ------------
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8 spring.jackson.time-zone=GMT+8
\ No newline at end of file
memcached.url=192.168.130.230:11211
\ No newline at end of file
...@@ -32,4 +32,6 @@ ribbon.ConnectTimeout=60000 ...@@ -32,4 +32,6 @@ ribbon.ConnectTimeout=60000
#------------ Please don't change above configurations ------------ #------------ Please don't change above configurations ------------
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8 spring.jackson.time-zone=GMT+8
\ No newline at end of file
memcached.url=192.168.130.230:11211
\ No newline at end of file
Markdown 格式
0% or
您添加了 0 到此讨论。请谨慎行事。
先完成此消息的编辑!
想要评论请 注册