Shiro集成Google Kaptcha验证码
程序员文章站
2022-06-28 16:36:57
Shiro集成Google Kaptcha验证码Kaptcha 简介Kaptcha 是一个可高度配置的实用验证码生成工具。Kaptcha 详细配置Constant描述默认值kaptcha.border图片边框,合法值:yes , noyeskaptcha.border.color边框颜色,合法值: r,g,b (and optional alpha) 或者 white,black,blue.blackkaptcha.border.thickness边框厚度,合法值:>01kaptcha.ima...
Shiro集成Google Kaptcha验证码
Kaptcha 简介
Kaptcha 是一个可高度配置的实用验证码生成工具。
Kaptcha 详细配置
Constant | 描述 | 默认值 |
kaptcha.border | 图片边框,合法值:yes , no | yes |
kaptcha.border.color | 边框颜色,合法值: r,g,b (and optional alpha) 或者 white,black,blue. | black |
kaptcha.border.thickness | 边框厚度,合法值:>0 | 1 |
kaptcha.image.width | 图片宽 | 200 |
kaptcha.image.height | 图片高 | 50 |
kaptcha.producer.impl | 图片实现类 | com.google.code.kaptcha.impl.DefaultKaptcha |
kaptcha.textproducer.impl | 文本实现类 | com.google.code.kaptcha.text.impl.DefaultTextCreator |
kaptcha.textproducer.char.string | 文本集合,验证码值从此集合中获取 | abcde2345678gfynmnpwx |
kaptcha.textproducer.char.length | 验证码长度 | 5 |
kaptcha.textproducer.font.names | 字体 | Arial, Courier |
kaptcha.textproducer.font.size | 字体大小 | 40px. |
kaptcha.textproducer.font.color | 字体颜色,合法值: r,g,b 或者 white,black,blue. | black |
kaptcha.textproducer.char.space | 文字间隔 | 2 |
kaptcha.noise.impl | 干扰实现类 | com.google.code.kaptcha.impl.DefaultNoise |
kaptcha.noise.color | 干扰 颜色,合法值: r,g,b 或者 white,black,blue. | black |
kaptcha.obscurificator.impl | 图片样式: 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy |
com.google.code.kaptcha.impl.WaterRipple |
kaptcha.background.impl | 背景实现类 | com.google.code.kaptcha.impl.DefaultBackground |
kaptcha.background.clear.from | 背景颜色渐变,开始颜色 | light grey |
kaptcha.background.clear.to | 背景颜色渐变, 结束颜色 | white |
kaptcha.word.impl | 文字渲染器 | com.google.code.kaptcha.text.impl.DefaultWordRenderer |
kaptcha.session.key | session key | KAPTCHA_SESSION_KEY |
kaptcha.session.date | session date | KAPTCHA_SESSION_DATE |
Maven 依赖
<!-- Google Kaptcha 验证码-->
<dependency>
<groupId>com.github.penggle</groupId>
<artifactId>kaptcha</artifactId>
<version>2.3.2</version>
</dependency>
配置
@Component
public class KaptchaConfig {
// 页面提交的验证码参数
public static final String LOGIN_KAPTCHA = "captcha";
// session中的验证码
public static final String SHIRO_VERIFY_SESSION = "verify_session_code";
@Bean
public DefaultKaptcha defaultKaptcha() {
DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
Properties properties = new Properties();
// 边框
properties.setProperty("kaptcha.border", "yes");
// 边框颜色
properties.setProperty("kaptcha.border.color", "105,179,90");
// 字体
properties.setProperty("kaptcha.textproducer.font.names", "宋体,楷体,黑体");
// 字体尺寸
properties.setProperty("kaptcha.textproducer.font.size", "26");
// 字体颜色
properties.setProperty("kaptcha.textproducer.font.color", "blue");
// 去掉干扰线
properties.setProperty("kaptcha.noise.impl", "com.google.code.kaptcha.impl.NoNoise");
// 图片宽度
properties.setProperty("kaptcha.image.width", "120");
// 图片高度
properties.setProperty("kaptcha.image.height", "30");
// 图片样式
properties.setProperty("kaptcha.obscurificator.impl", "com.google.code.kaptcha.impl.ShadowGimpy");
// 设置session key
properties.setProperty("kaptcha.session.key", "verification_session_key");
// 验证码长度
properties.setProperty("kaptcha.textproducer.char.length", "4");
Config config = new Config(properties);
defaultKaptcha.setConfig(config);
return defaultKaptcha;
}
}
Shiro拦截器
public class ShiroKaptchaFilter extends AccessControlFilter {
private static final String MESSAGE = "message";
// 错误后的跳转地址
private String loginUrl;
ShiroKaptchaFilter(String loginUrl){
this.loginUrl = loginUrl;
}
@Override
protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object o) {
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
// 清除此提示,防止重复提示
httpServletRequest.removeAttribute(MESSAGE);
// 因为登录为表单提交登录,此处判断是否为表单提交
if ("post".equalsIgnoreCase(httpServletRequest.getMethod())) {
Subject subject = SecurityUtils.getSubject();
String captcha__session = StringHelper.parse(subject.getSession().getAttribute(KaptchaConfig.SHIRO_VERIFY_SESSION), "");
// 判断session中的验证码是否为空,为空则说明可能为第一次进入登录页面
if (!StringHelper.isNullOrEmpty(captcha__session, true)) {
String captcha__param = httpServletRequest.getParameter(KaptchaConfig.LOGIN_KAPTCHA);
return captcha__session.equalsIgnoreCase(captcha__param);
}
}
return true;
}
@Override
protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
// 重定向到登录页,并给出提示
Map<String, String> queryParamMap = new HashMap<>();
queryParamMap.put(MESSAGE, "验证码错误");
WebUtils.issueRedirect(servletRequest, servletResponse, loginUrl, queryParamMap);
return false;
}
}
Shiro配置
@Bean
public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
ShiroFilterFactory shiroFilterFactoryBean = new ShiroFilterFactory();
// 必须设置 SecurityManager
shiroFilterFactoryBean.setSecurityManager(securityManager);
// 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
shiroFilterFactoryBean.setLoginUrl("/admin/login");
// 未授权界面;
shiroFilterFactoryBean.setUnauthorizedUrl("/admin/login");
// 登录成功后要跳转的链接
shiroFilterFactoryBean.setSuccessUrl("/admin");
Map<String, Filter> filterMap = new LinkedHashMap<>();
// 验证码过滤器
ShiroKaptchaFilter shiroKaptchaFilter = new ShiroKaptchaFilter("/admin/login");
filterMap.put("kaptcha", shiroKaptchaFilter);
//退出过滤器
SystemLogoutFilter systemLogoutFilter = new SystemLogoutFilter();
filterMap.put("logout", systemLogoutFilter);
shiroFilterFactoryBean.setFilters(filterMap);
//LinkedHashMap保证过滤顺序,前缀相同时先配置不会被拦截的链接,不能颠倒。
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
filterChainDefinitionMap.put("/admin/login/**", "kaptcha,anon");//验证码过滤器必须与登录确认在一起
filterChainDefinitionMap.put("/admin/logout", "logout");
filterChainDefinitionMap.put("/admin/**","authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
登录控制器验证码部分
@Controller
@RequestMapping("admin/login")
public class LoginController extends ControllerBase {
private static final Logger logger = LoggerFactory.getLogger(LoginController.class);
@Autowired
private DefaultKaptcha defaultKaptcha;
@RequestMapping(value = "captcha")
public void getCaptcha(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
try {
//生产验证码字符串并保存到session中
String createText = defaultKaptcha.createText();
httpServletRequest.getSession().setAttribute(KaptchaConfig.SHIRO_VERIFY_SESSION, createText);
//使用生产的验证码字符串返回一个BufferedImage对象并转为byte写入到byte数组中
BufferedImage bufferedImage = defaultKaptcha.createImage(createText);
ImageIO.write(bufferedImage, "jpg", byteArrayOutputStream);
//定义response输出类型为image/jpeg类型,使用response输出流输出图片的byte数组
httpServletResponse.setHeader("Cache-Control", "no-store");
httpServletResponse.setHeader("Pragma", "no-cache");
httpServletResponse.setDateHeader("Expires", 0);
httpServletResponse.setContentType("image/jpeg");
ServletOutputStream responseOutputStream = httpServletResponse.getOutputStream();
responseOutputStream.write(byteArrayOutputStream.toByteArray());
responseOutputStream.flush();
responseOutputStream.close();
} catch (IllegalArgumentException ex) {
httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND);
}
}
}
前端页面
在适当位置添加如下代码,注意这里input的name值为captcha,在Shiro拦截器器中会用到
<input type="text"
name="captcha"
data-required="true"
data-message="验证码不能为空"
autocomplete="OFF"
placeholder="请输入验证码"
/>
<img src="/admin/login/captcha"
class="j-col-x j-input-group"
style="float: right; width: 120px; height: 32px;"
alt="验证码"
onclick="this.src='/admin/login/captcha?d='+new Date()*1"
/>
本文地址:https://blog.csdn.net/qq_44977042/article/details/109829388
上一篇: 设计模式-装饰者模式
下一篇: 并发知识点整理