学习目标
如标题有如下两个功能实现:
个人博客:http://z77z.oschina.io/
此项目下载地址:https://git.oschina.net/z77z/springboot_mybatisplus
记住我
在ShiroConfig.java中添加如下方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| * cookie对象; * @return */ public SimpleCookie rememberMeCookie(){ SimpleCookie simpleCookie = new SimpleCookie("rememberMe"); simpleCookie.setMaxAge(2592000); return simpleCookie; } * cookie管理对象;记住我功能 * @return */ public CookieRememberMeManager rememberMeManager(){ CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager(); cookieRememberMeManager.setCookie(rememberMeCookie()); cookieRememberMeManager.setCipherKey(Base64.decode("3AvVhmFLUs0KTA3Kprsdag==")); return cookieRememberMeManager; }
|
rememberMeCookie()方法是设置Cookie的生成模版,比如cookie的name,cookie的有效时间等等。
rememberMeManager()方法是生成rememberMe管理器,而且要将这个rememberMe管理器设置到securityManager中,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13
| @Bean public SecurityManager securityManager() { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(myShiroRealm()); securityManager.setCacheManager(cacheManager()); securityManager.setSessionManager(SessionManager()); securityManager.setRememberMeManager(rememberMeManager()); return securityManager; }
|
其实上面的步骤,也就是rememberMe管理器可以不用配置,shiro会使用默认的配置,之所以要配置的目的是为了能够在实际业务环境中自定义其中的参数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| @RequestMapping(value="ajaxLogin",method=RequestMethod.POST) @ResponseBody public Map<String,Object> submitLogin(String username, String password,Boolean rememberMe,Model model) { Map<String, Object> resultMap = new LinkedHashMap<String, Object>(); try { UsernamePasswordToken token = new UsernamePasswordToken(username, password,rememberMe); SecurityUtils.getSubject().login(token); resultMap.put("status", 200); resultMap.put("message", "登录成功"); } catch (Exception e) { resultMap.put("status", 500); resultMap.put("message", e.getMessage()); } return resultMap; }
|
之前我是将shiro已经实现的UsernamePasswordToken类再封装了一层,最后发现没有必要,直接使用shiro提供的UsernamePasswordToken的类,其中有一个构造函数需要传rememberMe这个参数,也就是shiro为我们已经实现好了,推荐大家去看下UsernamePasswordToken这个类的源码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| <!DOCTYPE html> <%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path; %> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <script type="text/javascript" src="<%=basePath%>/static/js/jquery-1.11.3.js"></script> <title>登录</title> </head> <body> 错误信息: <h4 id="erro"></h4> <form> <p> 账号:<input type="text" name="username" id="username" value="admin" /> </p> <p> 密码:<input type="text" name="password" id="password" value="123" /> </p> <P><input type="checkbox" name="rememberMe" id="rememberMe" />记住我</P> <p> <input type="button" id="ajaxLogin" value="登录" /> </p> </form> </body> <script> $(function(){ $("#ajaxLogin").click(function() { var username = $("#username").val(); var password = $("#password").val(); var rememberMe =$('#rememberMe').is(':checked'); $.post("/ajaxLogin", { "username" : username, "password" : password, "rememberMe" : rememberMe }, function(result) { if (result.status == 200) { location.href = "/index"; } else { $("#erro").html(result.message); } }); }); }); </script> </html>
|
添加一个记住我的单选框,来控制是否需要记住我。
- 修改权限配置,修改sys_permission_init表
链接权限控制表
因为getGifCode是获取验证码的链接,所以要配置为anon,不需要权限验证。user权限是配置记住我或认证通过可以访问,所以将/**链接设置为user权限,就可以实现记住我的功能。
注意权限添加的排序。
GIF验证码
- 编写一个获取GIF验证码图片的controller:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| * 获取验证码(Gif版本) * @param response */ @RequestMapping(value="getGifCode",method=RequestMethod.GET) public void getGifCode(HttpServletResponse response,HttpServletRequest request){ try { response.setHeader("Pragma", "No-cache"); response.setHeader("Cache-Control", "no-cache"); response.setDateHeader("Expires", 0); response.setContentType("image/gif"); * gif格式动画验证码 * 宽,高,位数。 */ Captcha captcha = new GifCaptcha(146,33,4); captcha.out(response.getOutputStream()); HttpSession session = request.getSession(true); session.setAttribute("_code",captcha.text().toLowerCase()); } catch (Exception e) { System.err.println("获取验证码异常:"+e.getMessage()); } }
|
生成验证码后,将图片返回到页面,将字符串保存在当前会话的session域中。
这个GIF验证码的生成插件源码在我的项目io.z77z.vcode这个包下面,大家需要的话可以在我的码云上去下载。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| * ajax登录请求 * @param username * @param password * @return */ @RequestMapping(value="ajaxLogin",method=RequestMethod.POST) @ResponseBody public Map<String,Object> submitLogin(String username, String password,String vcode,Boolean rememberMe,Model model) { Map<String, Object> resultMap = new LinkedHashMap<String, Object>(); if(vcode==null||vcode==""){ resultMap.put("status", 500); resultMap.put("message", "验证码不能为空!"); return resultMap; } Session session = SecurityUtils.getSubject().getSession(); vcode = vcode.toLowerCase(); String v = (String) session.getAttribute("_code"); if(!vcode.equals(v)){ resultMap.put("status", 500); resultMap.put("message", "验证码错误!"); return resultMap; } try { UsernamePasswordToken token = new UsernamePasswordToken(username, password,rememberMe); SecurityUtils.getSubject().login(token); resultMap.put("status", 200); resultMap.put("message", "登录成功"); } catch (Exception e) { resultMap.put("status", 500); resultMap.put("message", e.getMessage()); } return resultMap; }
|
登录的时候判断前台传入的验证码和session中的是否一致。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| <!DOCTYPE html> <%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path; %> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <script type="text/javascript" src="<%=basePath%>/static/js/jquery-1.11.3.js"></script> <title>登录</title> </head> <body> 错误信息: <h4 id="erro"></h4> <form> <p> 账号:<input type="text" name="username" id="username" value="admin" /> </p> <p> 密码:<input type="text" name="password" id="password" value="123" /> </p> <p> 验证码:<input type="text" name="vcode" id="vcode"/> </p> <p> <img alt="验证码" src="/getGifCode"> </p> <P><input type="checkbox" name="rememberMe" id="rememberMe" />记住我</P> <p> <input type="button" id="ajaxLogin" value="登录" /> </p> </form> </body> <script> $(function(){ $("#ajaxLogin").click(function() { var username = $("#username").val(); var password = $("#password").val(); var vcode = $("#vcode").val(); var rememberMe =$('#rememberMe').is(':checked'); $.post("/ajaxLogin", { "username" : username, "password" : password, "vcode" : vcode, "rememberMe" : rememberMe }, function(result) { if (result.status == 200) { location.href = "/index"; } else { $("#erro").html(result.message); } }); }); }); </script> </html>
|
总结:
到此,我们集成shiro和redis,学习了一下功能的实现:
- 用户必须要登陆之后才能访问定义链接,否则跳转到登录页面,被禁用户不能登录。并且对一些敏感操作链接设置权限,只有满足权限的才可以访问。
- 每个链接的权限信息保存在数据库,可以动态进行设置,并且热加载权限。
- 使用redis对shiro的用户信息进行缓存,不用每次都去执行MyShiroRealm.doGetAuthorizationInfo()权限认证方法。
- 之前有很多同学下载我的项目时,运行会报错,那是因为最近都在不断修改提交,有可能会出现版本问题,现在我在我的码云上面创建了stable_version分支,都是可以跑起来的。sqltable放在resource目录下面。
- “记住我”的功能,利用cookie。
- GIF验证码的生成,在登陆时进行验证码的校验。利用session。
- 下一博,我应该会写对在线用户的管理,踢出登录的功能学习记录。
香蕉硬币点赞走一波啦。。。。。。
最后更新时间: