本文内容:Shiro 中RememberMe 功能的介绍以及实现。
1
介绍
Shiron 提供了记住我(RememberMe)的功能,比如访问如淘宝等一些网站时,关闭了浏览器下次再打开时还是能记住你是谁,下次访问时无需再登录即可访问。
基本流程如下:
1、首先在登录页面选中RememberMe然后登录成功;如果是浏览器登录,一般会把RememberMe的Cookie写到客户端并保存下来;
2、关闭浏览器再重新打开;会发现浏览器还是记住你的;
3、访问一般的网页服务器端还是知道你是谁,且能正常访问;
4、但是比如我们访问淘宝时,如果要查看我的订单或进行支付时,此时还是需要再进行身份认证的,以确保当前用户还是你。
关于拦截器
访问一般网页,如个人在主页之类的,我们使用user拦截器即可,user拦截器只要用户登录(isRemembered()==true||isAuthenticated()==true)
通过即可访问成功;
访问特殊网页,如我的订单,提交订单页面,我们使用authc
拦截器,authc
拦截器会判断用户是否是通过
Subject.login
(isAuthenticated()==true)
登录的,如果是才放行,否则会跳转到登录页面叫你重新登录。
关于rememberMe
的cookie
shiro
自动对用户对象序列化并加密. 当获得请求时, 能够获取反序列化且解密之后的用户对象。
当设置rememberMe==false
, 将会自动清空rememberMe cookie.
不想要自动登录怎么办?
调用shiro
的logout()
方法, 即消除自动登录功能。
2
实现
ShiroConfig.java
中添加配置
注意:
cookieRememberMeManager.setCipherKey
传入参数为长度16位的byte[],否则会报Unable to init cipher instance:无法初始化密码实例的错误。
/** * cookie对象; * @return */ public SimpleCookie rememberMeCookie(){ //这个参数是cookie的名称,对应前端的checkbox的name = rememberMe SimpleCookie simpleCookie = new SimpleCookie("rememberMe"); //cookie生效时间30天,单位秒; simpleCookie.setMaxAge(2592000); return simpleCookie; }
/** * cookie管理对象;记住我功能 * @return */ public CookieRememberMeManager rememberMeManager(){ CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager(); cookieRememberMeManager.setCookie(rememberMeCookie()); cookieRememberMeManager.setCipherKey("ZHANGXIAOHEI_CAT".getBytes()); return cookieRememberMeManager; }
注入到SecurityManager
@Bean(name="securityManager") public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm")UserRealm userRealm){ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); //关联realm securityManager.setRealm(userRealm); //使用记住我 securityManager.setRememberMeManager(rememberMeManager()); return securityManager; }
修改登录页面login.html
修改LoginController.java
@RequestMapping(value="/login",method = RequestMethod.GET) public String toLogin(Model model) { Subject subject = SecurityUtils.getSubject(); System.out.println(subject.isRemembered()); System.out.println(subject.isAuthenticated()); if(subject.isRemembered()){ System.out.println("-------------------------------------------------"); System.out.println("认证成功"); DzmHisMember member = (DzmHisMember)subject.getPrincipal(); model.addAttribute("member",member); return "redirect:/toHome"; } return "login"; }
@RequestMapping(value="/login",method = RequestMethod.POST) public String login(String userName,String password,boolean rememberMe,Model model) { /** * 使用Shiro编写认证操作 *///1.获取Subject Subject subject = SecurityUtils.getSubject(); //2.封装用户数据 UsernamePasswordToken token = new UsernamePasswordToken(userName,password);//3.执行登录方法 try { System.out.println(rememberMe); token.setRememberMe(rememberMe); subject.login(token); //登录成功,跳转到主页面 return "redirect:/toHome"; } catch (UnknownAccountException e) { //登录失败:用户名不存在 model.addAttribute("msg", "用户名不存在"); return "login"; }catch (IncorrectCredentialsException e) { //登录失败:密码错误 model.addAttribute("msg", "密码错误"); return "login"; } }
前一次登录勾选了记住我, 则本次登录时isRemembered()==true
(如果上一次设置了rememberme
, 本次登录是不会触发action
中的login()
的方法的, 即会直接进入登录状态)。
经过shiro
的login()
则表示为认证登录的. 就是说authentication==true
. 访问权限最高.
rememberMe==true
, 则将不会进入任何action. 可以访问所有user
控制的页面或路径. 但不能访问authc
控制的面或路径。
这里有个关键点:
subject.isAuthenticated()==true,则 subject.isRemembered()==false;
反之同理。
3
测试
在地址栏输入http://localhost:8080/hospital/login,第一次登陆时勾选“记住我”,登陆成功后关闭该页面;再在地址栏输入
http://localhost:8080/hospital/login会直接进入主页而不是登陆页面,控制台输出如下:
至此,本文结束。欢迎各位关注我的公众号:暗星涌动。