1:环境:idea 14版本,win10,springboot
2:第一个问题:必须使用shiro实现登录(加验证码)
参考资料: https://blog.csdn.net/qq_34021712/article/details/80470738 ©王赛超
验证码校验:
@RequestMapping(value = "/login",method = RequestMethod.POST) public String loginUser(HttpServletRequest request, String username, String password,boolean rememberMe,String captcha, Model model) { //校验验证码 //session中的验证码 String sessionCaptcha = (String) SecurityUtils.getSubject().getSession().getAttribute(CaptchaController.KEY_CAPTCHA); if (null == captcha || !captcha.equalsIgnoreCase(sessionCaptcha)) { model.addAttribute("msg","验证码错误!"); return "login"; } //对密码进行加密 //password=new SimpleHash("md5", password, ByteSource.Util.bytes(username.toLowerCase() + "shiro"),2).toHex(); //如果有点击 记住我 UsernamePasswordToken usernamePasswordToken=new UsernamePasswordToken(username,password,rememberMe); //UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username,password); Subject subject = SecurityUtils.getSubject(); try { //登录操作 subject.login(usernamePasswordToken); return "redirect:index"; } catch(Exception e) { //登录失败从request中获取shiro处理的异常信息 shiroLoginFailure:就是shiro异常类的全类名 String exception = (String) request.getAttribute("shiroLoginFailure"); if(e instanceof UnknownAccountException){ model.addAttribute("msg","用户名或密码错误!"); } if(e instanceof IncorrectCredentialsException){ model.addAttribute("msg","用户名或密码错误!"); } if(e instanceof LockedAccountException){ model.addAttribute("msg","账号已被锁定,请联系管理员!"); } //返回登录页面 return "login"; } }
此处我将此模块放在logincontroller里面专门处理登录操作;下面的为验证码的生成;新建一个CaptchaUtil将它放在utils下面,标黄的地方注意是你自己定义的路径
import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileOutputStream; import java.util.Random; import javax.imageio.ImageIO; /** * 验证码工具类 */ public class CaptchaUtil { // 随机产生的字符串 private static final String RANDOM_STRS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; private static final String FONT_NAME = "Fixedsys"; private static final int FONT_SIZE = 18; private Random random = new Random(); private int width = 80;// 图片宽 private int height = 25;// 图片高 private int lineNum = 50;// 干扰线数量 private int strNum = 4;// 随机产生字符数量 /** * 生成随机图片 */ public BufferedImage genRandomCodeImage(StringBuffer randomCode) { // BufferedImage类是具有缓冲区的Image类 BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR); // 获取Graphics对象,便于对图像进行各种绘制操作 Graphics g = image.getGraphics(); // 设置背景色 g.setColor(getRandColor(200, 250)); g.fillRect(0, 0, width, height); // 设置干扰线的颜色 g.setColor(getRandColor(110, 120)); // 绘制干扰线 for (int i = 0; i <= lineNum; i++) { drowLine(g); } // 绘制随机字符 g.setFont(new Font(FONT_NAME, Font.ROMAN_BASELINE, FONT_SIZE)); for (int i = 1; i <= strNum; i++) { randomCode.append(drowString(g, i)); } g.dispose(); return image; } /** * 给定范围获得随机颜色 */ private Color getRandColor(int fc, int bc) { if (fc > 255){ fc = 255; } if (bc > 255){ bc = 255; } int r = fc + random.nextInt(bc - fc); int g = fc + random.nextInt(bc - fc); int b = fc + random.nextInt(bc - fc); return new Color(r, g, b); } /** * 绘制字符串 */ private String drowString(Graphics g, int i) { g.setColor(new Color(random.nextInt(101), random.nextInt(111), random .nextInt(121))); String rand = String.valueOf(getRandomString(random.nextInt(RANDOM_STRS .length()))); g.translate(random.nextInt(3), random.nextInt(3)); g.drawString(rand, 13 * i, 16); return rand; } /** * 绘制干扰线 */ private void drowLine(Graphics g) { int x = random.nextInt(width); int y = random.nextInt(height); int x0 = random.nextInt(16); int y0 = random.nextInt(16); g.drawLine(x, y, x + x0, y + y0); } /** * 获取随机的字符 */ private String getRandomString(int num) { return String.valueOf(RANDOM_STRS.charAt(num)); } public static void main(String[] args) { CaptchaUtil tool = new CaptchaUtil(); StringBuffer code = new StringBuffer(); BufferedImage image = tool.genRandomCodeImage(code); System.out.println("random code = " + code); try { // 将内存中的图片通过流动形式输出到客户端 ImageIO.write(image, "JPEG", new FileOutputStream(new File( "/Users/wangsaichao/Desktop/random-code.jpg"))); } catch (Exception e) { e.printStackTrace(); } } }
登录界面的代码,如果是这样的话你会发现页面根本不会出现验证码,标黄部分是验证码刷新代码,你必须调用此方法来进行验证码的生成,标红部分为你的logincontroller里面的方法路径。
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro"> <head> <meta charset="UTF-8" /> <title>Insert title here</title> </head> <body> <h1>欢迎登录</h1> <h1 th:if="${msg != null }" th:text="${msg}" style="color: red"></h1> <form action="/login" method="post"> 用户名:<input type="text" name="username"/><br/> 密码:<input type="password" name="password"/><br/> 验证码:<input type="text" name="captcha"/><img alt="验证码" th:src="@{/Captcha.jpg}" title="点击更换" id="captcha_img"/> (看不清<a href="javascript:void(0)" onclick="javascript:refreshCaptcha()">换一张</a>)<br/> <input type="checkbox" name="rememberMe" />记住我<br/> <input type="submit" value="提交"/> <button><a href="/unlockAccount">解锁admin用户</a></button> </form> </body> <script type="text/javascript"> window.οnlοad=kickout(); 加上:
$(function(){ refreshCaptcha(); })
function refreshCaptcha(){ $("#captcha_img").attr("src","/Captcha.jpg?id=" + new Date() + Math.floor(Math.random()*24)); } </script> </html>
然后说说我遇到的问题:账号密码输入正确但是登陆不了,原因就是shiro默认会将你的密码进行md5加密,匹配的时候要么将shiro的md5加密去掉,要么就是将密码进行md5加密后再进行匹配。shiro是不需要你进行数据库查找的,他默认的进行了这一操作。
3.第二个问题,普遍的跳转
方式有多种,这里只说的是controller里面的跳转:
@RequestMapping("/") public String index() { return "login"; } @RequestMapping("/") public String index() { return "redirect:/login"; }
上述的两种跳转是比较多的,第一种,直接return,那么它是找的你的.jsp文件。第二种,redirect:/login解释为重定向,他会在controller里面找到相应的以RequestMapping("/login")为开头的方法。然后进行跳转。
另外的涉及到页面的相互传值的问题(跳转),以一个案例来分析
logincontroller里面@RequestMapping("/edit") public String userEdit(Model model, HttpServletRequest request) { String id = request.getParameter("id"); int userid = Integer.parseInt(id); 方法 model.addAttribute("user", uservo);传值方式 return "页面"; } @RequestMapping("/editUser") @ResponseBody public ResultVo edit(UserEntity userEntity) { ResultVo result = new ResultVo(); 方法 if (CommonUtil.isNotNull(userVo)) { result.setSuccess(false); } else { result.setSuccess(true); } return result; } 页面主要的ajax传值代码 $.ajax({ type: "POST", async: "false", dataType1: "json", data : t, url: "${root}/user/editUser", //传入值 success: function (data) { if(data.success){ window.location.href ='${root}/edit'; //跳转界面 } } });
流程为:主页面加载完成:点击编辑按钮,在editUser里面进行判断,返回的result为true和false,如果返回为true则会跳转到edit,edit跳转到相应的页面。