Java中SSM+Shiro系统登录验证码的实现方法
程序员文章站
2024-03-07 19:49:21
先给大家展示下效果图:
1、验证码生成类:
import java.util.random;
import java.awt.image.bu...
先给大家展示下效果图:
1、验证码生成类:
import java.util.random; import java.awt.image.bufferedimage; import java.awt.graphics; import java.awt.font; import java.awt.color; /** * 验证码生成器类,可生成数字、大写、小写字母及三者混合类型的验证码。 支持自定义验证码字符数量; 支持自定义验证码图片的大小; 支持自定义需排除的特殊字符; * 支持自定义干扰线的数量; 支持自定义验证码图文颜色 */ public class validatecode { /** * 验证码类型为仅数字 0~9 */ public static final int type_num_only = 0; /** * 验证码类型为仅字母,即大写、小写字母混合 */ public static final int type_letter_only = 1; /** * 验证码类型为数字、大写字母、小写字母混合 */ public static final int type_all_mixed = 2; /** * 验证码类型为数字、大写字母混合 */ public static final int type_num_upper = 3; /** * 验证码类型为数字、小写字母混合 */ public static final int type_num_lower = 4; /** * 验证码类型为仅大写字母 */ public static final int type_upper_only = 5; /** * 验证码类型为仅小写字母 */ public static final int type_lower_only = 6; private validatecode() { } /** * 生成验证码字符串 * * @param type * 验证码类型,参见本类的静态属性 * @param length * 验证码长度,大于0的整数 * @param exchars * 需排除的特殊字符(仅对数字、字母混合型验证码有效,无需排除则为null) * @return 验证码字符串 */ public static string generatetextcode(int type, int length, string exchars) { if (length <= 0) return ""; stringbuffer code = new stringbuffer(); int i = 0; random r = new random(); switch (type) { // 仅数字 case type_num_only: while (i < length) { int t = r.nextint(10); if (exchars == null || exchars.indexof(t + "") < 0) {// 排除特殊字符 code.append(t); i++; } } break; // 仅字母(即大写字母、小写字母混合) case type_letter_only: while (i < length) { int t = r.nextint(123); if ((t >= 97 || (t >= 65 && t <= 90)) && (exchars == null || exchars.indexof((char) t) < 0)) { code.append((char) t); i++; } } break; // 数字、大写字母、小写字母混合 case type_all_mixed: while (i < length) { int t = r.nextint(123); if ((t >= 97 || (t >= 65 && t <= 90) || (t >= 48 && t <= 57)) && (exchars == null || exchars.indexof((char) t) < 0)) { code.append((char) t); i++; } } break; // 数字、大写字母混合 case type_num_upper: while (i < length) { int t = r.nextint(91); if ((t >= 65 || (t >= 48 && t <= 57)) && (exchars == null || exchars.indexof((char) t) < 0)) { code.append((char) t); i++; } } break; // 数字、小写字母混合 case type_num_lower: while (i < length) { int t = r.nextint(123); if ((t >= 97 || (t >= 48 && t <= 57)) && (exchars == null || exchars.indexof((char) t) < 0)) { code.append((char) t); i++; } } break; // 仅大写字母 case type_upper_only: while (i < length) { int t = r.nextint(91); if ((t >= 65) && (exchars == null || exchars.indexof((char) t) < 0)) { code.append((char) t); i++; } } break; // 仅小写字母 case type_lower_only: while (i < length) { int t = r.nextint(123); if ((t >= 97) && (exchars == null || exchars.indexof((char) t) < 0)) { code.append((char) t); i++; } } break; } return code.tostring(); } /** * 已有验证码,生成验证码图片 * * @param textcode * 文本验证码 * @param width * 图片宽度 * @param height * 图片高度 * @param interline * 图片中干扰线的条数 * @param randomlocation * 每个字符的高低位置是否随机 * @param backcolor * 图片颜色,若为null,则采用随机颜色 * @param forecolor * 字体颜色,若为null,则采用随机颜色 * @param linecolor * 干扰线颜色,若为null,则采用随机颜色 * @return 图片缓存对象 */ public static bufferedimage generateimagecode(string textcode, int width, int height, int interline, boolean randomlocation, color backcolor, color forecolor, color linecolor) { bufferedimage bim = new bufferedimage(width, height, bufferedimage.type_int_rgb); graphics g = bim.getgraphics(); // 画背景图 g.setcolor(backcolor == null ? getrandomcolor() : backcolor); g.fillrect(0, 0, width, height); // 画干扰线 random r = new random(); if (interline > 0) { int x = 0, y = 0, x1 = width, y1 = 0; for (int i = 0; i < interline; i++) { g.setcolor(linecolor == null ? getrandomcolor() : linecolor); y = r.nextint(height); y1 = r.nextint(height); g.drawline(x, y, x1, y1); } } // 写验证码 // g.setcolor(getrandomcolor()); // g.setcolor(issimplecolor?color.black:color.white); // 字体大小为图片高度的80% int fsize = (int) (height * 0.8); int fx = height - fsize; int fy = fsize; g.setfont(new font("default", font.plain, fsize)); // 写验证码字符 for (int i = 0; i < textcode.length(); i++) { fy = randomlocation ? (int) ((math.random() * 0.3 + 0.6) * height) : fy;// 每个字符高低是否随机 g.setcolor(forecolor == null ? getrandomcolor() : forecolor); g.drawstring(textcode.charat(i) + "", fx, fy); fx += fsize * 0.9; } g.dispose(); return bim; } /** * 生成图片验证码 * * @param type * 验证码类型,参见本类的静态属性 * @param length * 验证码字符长度,大于0的整数 * @param exchars * 需排除的特殊字符 * @param width * 图片宽度 * @param height * 图片高度 * @param interline * 图片中干扰线的条数 * @param randomlocation * 每个字符的高低位置是否随机 * @param backcolor * 图片颜色,若为null,则采用随机颜色 * @param forecolor * 字体颜色,若为null,则采用随机颜色 * @param linecolor * 干扰线颜色,若为null,则采用随机颜色 * @return 图片缓存对象 */ public static bufferedimage generateimagecode(int type, int length, string exchars, int width, int height, int interline, boolean randomlocation, color backcolor, color forecolor, color linecolor) { string textcode = generatetextcode(type, length, exchars); bufferedimage bim = generateimagecode(textcode, width, height, interline, randomlocation, backcolor, forecolor, linecolor); return bim; } /** * 产生随机颜色 * * @return */ private static color getrandomcolor() { random r = new random(); color c = new color(r.nextint(255), r.nextint(255), r.nextint(255)); return c; } }
2、controller
/** * 生成验证码 * @param request * @param response * @throws ioexception * @validatecode.generatetextcode(验证码字符类型,验证码长度,需排除的特殊字符) * @validatecode.generateimagecode(文本验证码,图片宽度,图片高度,干扰线的条数,字符的高低位置是否随机,图片颜色,字体颜色,干扰线颜色) */ @requestmapping(value = "validatecode") public void validatecode(httpservletrequest request, httpservletresponse response) throws ioexception { response.setheader("cache-control", "no-cache"); string verifycode = validatecode.generatetextcode(validatecode.type_num_lower, 4, null); request.getsession().setattribute("validatecode", verifycode); response.setcontenttype("image/jpeg"); bufferedimage bim = validatecode.generateimagecode(verifycode, 90, 30, 5, true, color.white, color.blue, null); imageio.write(bim, "jpeg", response.getoutputstream()); } /** * 登录请求 * @param */ @requestmapping(value = "login", method = requestmethod.post, produces = "text/html; charset=utf-8") public string login(httpservletrequest request, httpservletresponse response, userentity user) { //首先进行验证码验证 session session = securityutils.getsubject().getsession(); string code = (string) session.getattribute("validatecode"); string submitcode = webutils.getcleanparam(request, "validatecode"); if (stringutils.isempty(submitcode) || !stringutils.equals(code,submitcode.tolowercase())) { request.setattribute("login_error_code", loginconstant.login_error_code_100000); request.setattribute("login_error_message", loginconstant.login_error_message_validatecode); return "login"; } // 想要得到 securityutils.getsubject() 的对象..访问地址必须跟shiro的拦截地址内.不然后会报空指针 subject sub = securityutils.getsubject(); // 用户输入的账号和密码,,存到usernamepasswordtoken对象中..然后由shiro内部认证对比, // 认证执行者交由shirodbrealm中dogetauthenticationinfo处理 // 当以上认证成功后会向下执行,认证失败会抛出异常 usernamepasswordtoken token = new usernamepasswordtoken(user.getaccountname(), user.getpassword()); try { sub.login(token); } catch (lockedaccountexception lae) { token.clear(); request.setattribute("login_error_code", loginconstant.login_error_code_100002); request.setattribute("login_error_message", loginconstant.login_error_message_systemerror); return "login"; } catch (excessiveattemptsexception e) { token.clear(); request.setattribute("login_error_code", loginconstant.login_error_code_100003); request.setattribute("login_error_message","账号:" + user.getusername() + loginconstant.login_error_message_maxerror); return "login"; } catch (authenticationexception e) { token.clear(); request.setattribute("login_error_code", loginconstant.login_error_code_100001); request.setattribute("login_error_message", loginconstant.login_error_message_usererror); return "login"; } return "redirect:/index.shtml"; }
注意:
登录方法里面一些参数的定义:
public interface loginconstant { string login_error_code_100000 = "100000"; string login_error_message_validatecode = "验证码输入错误,请重新输入!"; string login_error_code_100001 = "100001"; string login_error_message_usererror = "账号或密码错误,请重新输入!"; string login_error_code_100002 = "100002"; string login_error_message_systemerror = "用户已经被锁定不能登录,请与管理员联系!"; string login_error_code_100003 = "100003"; string login_error_message_maxerror = "登录失败次数过多,锁定10分钟!"; string login_error_code_100004 = "100004"; string login_error_message_forcelogout = "您已经被管理员强制退出,请重新登录"; }
3、登录jsp(重要代码)
路径信息:
<% string path = request.getcontextpath(); string basepath = request.getscheme()+"://"+request.getservername()+":"+request.getserverport()+path; %>
js:用于更换验证码图片
<script> function reloadvalidatecode(){ $("#validatecodeimg").attr("src","<%=basepath%>/validatecode.shtml?data=" + new date() + math.floor(math.random()*24)); } </script>
登录表单里面的标签:
<img id="validatecodeimg" src="<%=basepath%>/validatecode.shtml" /> <a href="#" rel="external nofollow" onclick="javascript:reloadvalidatecode();">看不清?</a>
4、shiro匿名访问配置(不配置无法生成验证码图片)
<!--自定义filterchaindefinitionmap --> <bean id="chaindefinitionsectionmetasource" class="com.collection.shiro.chaindefinitionsectionmetasource"> <property name="filterchaindefinitions"> <value> /validatecode.shtml = anon//添加这行 </value> </property> </bean>
以上所述是小编给大家介绍的java中ssm+shiro系统登录验证码的实现方法,希望对大家有所帮助