验证码、MD5加密
验证码
生成验证码帮助类
点击查看代码VerifyCodeServlet.java
package com.situ.web.servlet; import java.awt.Color; import java.awt.Font; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.io.IOException; import java.io.OutputStream; import java.util.Random; import javax.imageio.ImageIO; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; /** * 验证码生成程序 * */ @WebServlet("/verifyCode") public class VerifyCodeServlet extends HttpServlet { private static final long serialVersionUID = 2376992603034716655L; private final Font mFont = new Font("Arial Black", Font.PLAIN, 15); // 设置字体 private final int lineWidth = 2; // 干扰线的长度=1.414*lineWidth private final int width = 88; // 定义图形大小 private final int height = 25; // 定义图形大小 private final int count = 200; /** * 描述: * * @param fc * 描述: * @param bc * 描述: * * @return 描述: */ private Color getRandColor(int fc, int bc) { // 取得给定范围随机颜色 final Random random = new Random(); if (fc > 255) { fc = 255; } if (bc > 255) { bc = 255; } final int r = fc + random.nextInt(bc - fc); final int g = fc + random.nextInt(bc - fc); final int b = fc + random.nextInt(bc - fc); return new Color(r, g, b); } // 处理post @Override public void doPost(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } /** * 描述: * * @param request * 描述: * @param response * 描述: * * @throws ServletException * 描述: * @throws IOException * 描述: */ @Override public void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException { response.reset(); // 设置页面不缓存 response.setHeader("Pragma", "No-cache"); response.setHeader("Cache-Control", "no-cache"); response.setDateHeader("Expires", 0); response.setContentType("image/gif"); // 在内存中创建图象 final BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); // 获取图形上下文 final Graphics2D g = (Graphics2D) image.getGraphics(); // 生成随机类 final Random random = new Random(); // 设定背景色 g.setColor(getRandColor(200, 250)); // ---1 g.fillRect(0, 0, width, height); // 设定字体 g.setFont(mFont); // 画边框 g.setColor(getRandColor(0, 20)); // ---2 // 距离 g.drawRect(0, 0, width - 1, height - 1); // 随机产生干扰线,使图象中的认证码不易被其它程序探测到 for (int i = 0; i < count; i++) { g.setColor(getRandColor(150, 200)); // ---3 final int x = random.nextInt(width - lineWidth - 1) + 1; // 保证画在边框之内 final int y = random.nextInt(height - lineWidth - 1) + 1; final int xl = random.nextInt(lineWidth); final int yl = random.nextInt(lineWidth); g.drawLine(x, y, x + xl, y + yl); } // 取随机产生的认证码(4位数字) String sRand = ""; for (int i = 0; i < 4; i++) { final String rand = String.valueOf(random.nextInt(10)); sRand += rand; // 将认证码显示到图象中,调用函数出来的颜色相同,可能是因为种子太接近,所以只能直接生成 g.setColor(new Color(20 + random.nextInt(130), 20 + random.nextInt(130), 20 + random.nextInt(130))); // --4--50-100 // 第一个参数是要画上去的字符串 后面两个参数是针对 (0,0) x轴和y轴 g.drawString(rand, (13 * i) + 10, 20); } // 把后台生成的验证码放到Session HttpSession session = request.getSession(); session.setAttribute("codeInSession", sRand); // 图象生效 // 它的作用是销毁程序中指定的图形界面资源,如果在使用了graphics获得windows一些图形资源,而不进行关闭的话,由于后期多人使用就会造成内存溢出的情况的,导致程序卡死。 g.dispose(); OutputStream os = response.getOutputStream(); // 输出图象到页面 ImageIO.write(image, "PNG", os); os.flush(); os.close(); } }
前端
前端展示
点击查看代码
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %> <%@ include file="header.jsp"%> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>登录</title> <script type="text/javascript"> let alert_msg = '${alert_msg}'; if (alert_msg != null && alert_msg.trim() != '') { window.alert(alert_msg); } </script> <style> * { padding: 0; margin: 0; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; letter-spacing: .05em; } html { height: 100%; } body { height: 100%; background: url("${path}/static/img/1.jpg") no-repeat; background-size: 100% 100%; } .container { height: 100%; /*background-image: linear-gradient(to right, #fbc2eb, #a6c1ee); 设置渐变色 */ padding: 0; margin: 0; } .login-wrapper { background-color: #fff; width: 300px; height: 500px; position: relative; padding: 0 50px; border-radius: 15px; /* 设置框的居中位置也可以采用flex布局方式 */ left: 50%; top: 50%; transform: translate(-50%, -50%); } .login-wrapper .header { font-size: 30px; font-weight: bold; text-align: center; line-height: 120px; } .login-wrapper .form-wrapper .input-item { display: block; width: 100%; margin-bottom: 20px; border: 0; padding: 10px; border-bottom: 1px solid rgb(128, 125, 125); font-size: 15px; outline: none; } .login-wrapper .form-wrapper .input-item ::placeholder { text-transform: uppercase; } .login-wrapper .form-wrapper .btn { text-align: center; padding: 10px; margin-top: 40px; width: 100%; background-image: linear-gradient(to right, #a6c1ee, #fbc2eb); color: #fff; } .login-wrapper .msg { text-align: center; line-height: 80px; } .login-wrapper .msg a { /* 消除下划线 */ text-decoration: none; text-decoration-color: unset; color: #a6c1ee; } </style> </head>
前端逻辑
<body> <div class="container"> <div class="login-wrapper"> <div class="header">Login</div> <div class="form-wrapper"> <form id="formId" method="post" onsubmit="return check()"> <input type="text" name="name" id="name" placeholder="登录账号" class="input-item"> <input type="password" name="password" id="password" placeholder="登录密码" class="input-item"> <input type="text" name="code" id="validationCode" placeholder="请输入验证码" class="input-item"> <img id="img_validation_code" src="${path}/auth" onclick="refresh()" /> <input class="btn" type="button" onclick="submitForm()" value="登录"/> </form> </div> <div class="msg"> Don't have account?<a href='register.jsp' style="font-weight: bold;">Sign up</a> </div> </div> </div> </body> <script type="text/javascript"> function submitForm(){ $.post( '${path}/login?method=login', $('#formId').serialize(),//{'name':'zhansagn','age':23,'gender':'男'} function (jsonResult){ console.log(jsonResult) if (jsonResult.ok){ mylayer.okUrl('登录成功','${path}/index.jsp') }else{ mylayer.errorMsg(jsonResult.msg) } } ) } </script> </html>
后端业务逻辑
private void login(HttpServletRequest req, HttpServletResponse resp) { System.out.println("UserServlet.login"); String name = req.getParameter("name"); String password = req.getParameter("password"); String code = req.getParameter("code"); //先判断验证码是否正确 HttpSession session = req.getSession(); String codeInSession = (String) session.getAttribute("codeInSession"); //验证码错误,返回错误信息 if(StringUtils.isEmpty(code)||!codeInSession.equalsIgnoreCase(code)){ JSONUtil.obj2Json(JSONResult.error("验证码为空或错误"),resp); return; } //验证码正确,验证用户名和 密码是否正确 User user=userService.login(name,password); if (user!=null) { JSONUtil.obj2Json(JSONResult.ok("登录成功"), resp); } else { JSONUtil.obj2Json(JSONResult.error("用户名或密码错误"), resp); } }
MD5加密
MD5特性:
MD5不管你加密多少的东西,哪怕是10M文件都能加密为32位的字符串。
并且神奇的是 :数学上能保证,哪怕你只改变了1个文字,加密后的字符串都会有很大变化。
MD5常见用途:
- 加密密码
- 对比文件。(保证客户端下载的文件和服务器文件是一个,防止下载假的文件。)
- 网盘的文件秒传
为什么要使用MD5加密密码:
- 脱库:是吧一个网站的数据库拖回来,就是把数据导出保存。
- 撞库:是用拖回来的用户数据取尝试登陆别的网站,撞上了就撞上了,撞不上就拉倒。
加密解密的原则:一个加密算法就是让全世界都知道了也无法破解,这才是牛的算法。
MD5加密是不能够被破解的。
所以找回密码功能:
- 如果这个网站使用的是MD5加密的,
那么这个密码是根本找不回来,找回密码是做成重置密码。 - 如果某个网站真能找回来,
说明这个网站肯定是明文保存的。
MD5是不能够被破解的,如果说MD5能够被“破解”:有另外的一个明文字符串加密之后也是这个值,但是这个概率小2的128次方。
王小云并不是完成了MD5的破解,而是加速了MD5值碰撞速度。
MD5是无法根据MD5值反推原始字符串的,但是有一定的概率有另一个不同的字符串,也能生成同样的MD5值,用户不需要输入原来密码也能登录系统。
王小云做的其实就是大大减少了找到这样一个加密后MD5值一样的字符串的时间。
MD5加密帮助类
点击查看代码MD5Util.java
package study.utils; import java.security.MessageDigest; /** * MD5工具类 */ public class MD5Util { //加盐 public static final String MD5_SALT = "sdut"; private static String byteArrayToHexString(byte b[]) { StringBuffer resultSb = new StringBuffer(); for (int i = 0; i < b.length; i++) resultSb.append(byteToHexString(b[i])); return resultSb.toString(); } private static String byteToHexString(byte b) { int n = b; if (n < 0) n += 256; int d1 = n / 16; int d2 = n % 16; return hexDigits[d1] + hexDigits[d2]; } /** * 返回大写MD5 * * @param origin * @param charsetname * @return */ public static String MD5Encode(String origin, String charsetname) { String resultString = null; try { resultString = new String(origin); MessageDigest md = MessageDigest.getInstance("MD5"); if (charsetname == null || "".equals(charsetname)) { resultString = byteArrayToHexString(md.digest(resultString.getBytes())); } else { resultString = byteArrayToHexString(md.digest(resultString.getBytes(charsetname))); } } catch (Exception exception) { } return resultString.toUpperCase(); } public static String MD5Encode(String origin) { return MD5Encode(origin, "utf-8"); } private static final String hexDigits[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"}; }
MD5使用
添加用户时加密
@Override public Boolean add(User user) { //添加用户时以密文形式添加到数据库 user.setPassword(MD5Util.MD5Encode(user.getPassword()+MD5Util.MD5_SALT)); int count=userDao.add(user); return count==1; }
修改用户时加密
····
登录时加密
@Override public User login(String name, String password) { //登录时加密密码 return userDao.selectByNameAndPassword(name,MD5Util.MD5Encode(password+MD5Util.MD5_SALT)); }
本文作者:kingwzun
本文链接:https://www.cnblogs.com/kingwz/p/16993937.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步