diff --git a/bootdo/src/main/java/com/bootdo/common/utils/RandomValidateCodeUtil.java b/bootdo/src/main/java/com/bootdo/common/utils/RandomValidateCodeUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..1a634fc2bb5b750495473ed49166e351452c044f --- /dev/null +++ b/bootdo/src/main/java/com/bootdo/common/utils/RandomValidateCodeUtil.java @@ -0,0 +1,122 @@ +package com.bootdo.common.utils; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.imageio.ImageIO; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.util.Random; + +/** + * @author bootdo + */ +public class RandomValidateCodeUtil { + + + public static final String RANDOMCODEKEY = "RANDOMVALIDATECODEKEY";//放到session中的key + private String randString = "0123456789";//随机产生只有数字的字符串 private String + //private String randString = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";//随机产生只有字母的字符串 + //private String randString = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";//随机产生数字与字母组合的字符串 + private int width = 95;// 图片宽 + private int height = 25;// 图片高 + private int lineSize = 40;// 干扰线数量 + private int stringNum = 4;// 随机产生字符数量 + + private static final Logger logger = LoggerFactory.getLogger(RandomValidateCodeUtil.class); + + private Random random = new Random(); + + /** + * 获得字体 + */ + private Font getFont() { + return new Font("Fixedsys", Font.CENTER_BASELINE, 18); + } + + /** + * 获得颜色 + */ + private Color getRandColor(int fc, int bc) { + if (fc > 255) { + fc = 255; + } + if (bc > 255) { + bc = 255; + } + int r = fc + random.nextInt(bc - fc - 16); + int g = fc + random.nextInt(bc - fc - 14); + int b = fc + random.nextInt(bc - fc - 18); + return new Color(r, g, b); + } + + /** + * 生成随机图片 + */ + public void getRandcode(HttpServletRequest request, HttpServletResponse response) { + HttpSession session = request.getSession(); + // BufferedImage类是具有缓冲区的Image类,Image类是用于描述图像信息的类 + BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR); + Graphics g = image.getGraphics();// 产生Image对象的Graphics对象,改对象可以在图像上进行各种绘制操作 + g.fillRect(0, 0, width, height);//图片大小 + g.setFont(new Font("Times New Roman", Font.ROMAN_BASELINE, 18));//字体大小 + g.setColor(getRandColor(110, 133));//字体颜色 + // 绘制干扰线 + for (int i = 0; i <= lineSize; i++) { + drowLine(g); + } + // 绘制随机字符 + String randomString = ""; + for (int i = 1; i <= stringNum; i++) { + randomString = drowString(g, randomString, i); + } + logger.info(randomString); + //将生成的随机字符串保存到session中 + session.removeAttribute(RANDOMCODEKEY); + session.setAttribute(RANDOMCODEKEY, randomString); + g.dispose(); + try { + // 将内存中的图片通过流动形式输出到客户端 + ImageIO.write(image, "JPEG", response.getOutputStream()); + } catch (Exception e) { + logger.error("将内存中的图片通过流动形式输出到客户端失败>>>> ", e); + } + + } + + /** + * 绘制字符串 + */ + private String drowString(Graphics g, String randomString, int i) { + g.setFont(getFont()); + g.setColor(new Color(random.nextInt(101), random.nextInt(111), random + .nextInt(121))); + String rand = String.valueOf(getRandomString(random.nextInt(randString + .length()))); + randomString += rand; + g.translate(random.nextInt(3), random.nextInt(3)); + g.drawString(rand, 13 * i, 16); + return randomString; + } + + /** + * 绘制干扰线 + */ + private void drowLine(Graphics g) { + int x = random.nextInt(width); + int y = random.nextInt(height); + int xl = random.nextInt(13); + int yl = random.nextInt(15); + g.drawLine(x, y, x + xl, y + yl); + } + + /** + * 获取随机的字符 + */ + public String getRandomString(int num) { + return String.valueOf(randString.charAt(num)); + } +} diff --git a/bootdo/src/main/java/com/bootdo/system/config/ShiroConfig.java b/bootdo/src/main/java/com/bootdo/system/config/ShiroConfig.java index 083410f6b517b64077dfe24a1ab03a4f233f93a6..c58b2af7f7bfdbeb8d54a57d5b975be6b9aab209 100644 --- a/bootdo/src/main/java/com/bootdo/system/config/ShiroConfig.java +++ b/bootdo/src/main/java/com/bootdo/system/config/ShiroConfig.java @@ -74,6 +74,7 @@ public class ShiroConfig { shiroFilterFactoryBean.setUnauthorizedUrl("/403"); LinkedHashMap filterChainDefinitionMap = new LinkedHashMap<>(); filterChainDefinitionMap.put("/login","anon"); + filterChainDefinitionMap.put("/getVerify","anon"); filterChainDefinitionMap.put("/css/**", "anon"); filterChainDefinitionMap.put("/js/**", "anon"); filterChainDefinitionMap.put("/fonts/**", "anon"); diff --git a/bootdo/src/main/java/com/bootdo/system/controller/LoginController.java b/bootdo/src/main/java/com/bootdo/system/controller/LoginController.java index 6d6aa5f87aa7e3504b462607fee88c784710d48d..bfb77924f2af5597a621a451b69322ee60310b31 100644 --- a/bootdo/src/main/java/com/bootdo/system/controller/LoginController.java +++ b/bootdo/src/main/java/com/bootdo/system/controller/LoginController.java @@ -6,9 +6,7 @@ import com.bootdo.common.controller.BaseController; import com.bootdo.common.domain.FileDO; import com.bootdo.common.domain.Tree; import com.bootdo.common.service.FileService; -import com.bootdo.common.utils.MD5Utils; -import com.bootdo.common.utils.R; -import com.bootdo.common.utils.ShiroUtils; +import com.bootdo.common.utils.*; import com.bootdo.system.domain.MenuDO; import com.bootdo.system.service.MenuService; import io.swagger.models.auth.In; @@ -23,8 +21,11 @@ import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; import java.util.List; @Controller @@ -74,8 +75,22 @@ public class LoginController extends BaseController { @Log("登录") @PostMapping("/login") @ResponseBody - R ajaxLogin(String username, String password) { + R ajaxLogin(String username, String password,String verify,HttpServletRequest request) { + try { + //从session中获取随机数 + String random = (String) request.getSession().getAttribute(RandomValidateCodeUtil.RANDOMCODEKEY); + if (StringUtils.isBlank(verify)) { + return R.error("请输入验证码"); + } + if (random.equals(verify)) { + } else { + return R.error("请输入正确的验证码"); + } + } catch (Exception e) { + logger.error("验证码校验失败", e); + return R.error("验证码校验失败"); + } password = MD5Utils.encrypt(username, password); UsernamePasswordToken token = new UsernamePasswordToken(username, password); Subject subject = SecurityUtils.getSubject(); @@ -98,4 +113,21 @@ public class LoginController extends BaseController { return "main"; } + /** + * 生成验证码 + */ + @GetMapping(value = "/getVerify") + public void getVerify(HttpServletRequest request, HttpServletResponse response) { + try { + response.setContentType("image/jpeg");//设置相应类型,告诉浏览器输出的内容为图片 + response.setHeader("Pragma", "No-cache");//设置响应头信息,告诉浏览器不要缓存此内容 + response.setHeader("Cache-Control", "no-cache"); + response.setDateHeader("Expire", 0); + RandomValidateCodeUtil randomValidateCode = new RandomValidateCodeUtil(); + randomValidateCode.getRandcode(request, response);//输出验证码图片方法 + } catch (Exception e) { + logger.error("获取验证码失败>>>> ", e); + } + } + } diff --git a/bootdo/src/main/resources/templates/login.html b/bootdo/src/main/resources/templates/login.html index 4970bf0d0f4ab1893e7921e65bddfe9f59382886..64db799d4becd36bc775190ad53634fb8735ad9d 100644 --- a/bootdo/src/main/resources/templates/login.html +++ b/bootdo/src/main/resources/templates/login.html @@ -60,6 +60,18 @@ 登录 +
+
+
+ +
+
+
+ + 更换验证码 + +
+
- + @@ -102,14 +115,19 @@ - + diff --git a/bootdo/src/main/resources/templates/system/menu/menu.html b/bootdo/src/main/resources/templates/system/menu/menu.html index cc8a7034103c6491056e45e6894541b54e299a9d..78ca74b9bdf93899634a647f890d0636be5bb884 100644 --- a/bootdo/src/main/resources/templates/system/menu/menu.html +++ b/bootdo/src/main/resources/templates/system/menu/menu.html @@ -36,12 +36,12 @@ s_add_h = ''; -
+
-
+