目录

  • 前言
  • `springboot` 整合 `shiro` 之实现记住我
    • 配置类 `ShiroConfig`
    • `login.html` 登录页面
    • `controller`
      • `UserVO` 类
  • 测试

前言

上一篇 文章我们完成了在 thymeleaf 模板引擎中使用 shiro 标签,也就是根据不同的用户身份信息,前端页面来显示不同的页面内容。本篇文章我们来完成在登录页面的记住我的功能

springboot 整合 shiro 之实现记住我

项目依然使用 springboot整合shiro 这个项目,稍稍改动即可完成记住我的功能

配置类 ShiroConfig

完整的代码如下

@Configuration
public class ShiroConfig {/*** 安全管理器** @param userRealm userRealm* @return defaultWebSecurityManager*/@Beanpublic DefaultWebSecurityManager getDefaultWebSecurityManager(UserRealm userRealm) {DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();defaultWebSecurityManager.setRealm(userRealm);// 实现记住我,所需要的配置defaultWebSecurityManager.setRememberMeManager(cookieRememberMeManager());return defaultWebSecurityManager;}/*** thymeleaf模板引擎中使用shiro标签时,要用到** @return*/@Beanpublic ShiroDialect getShiroDialect() {return new ShiroDialect();}@Beanpublic ShiroFilterFactoryBean shiroFilter(DefaultWebSecurityManager defaultWebSecurityManager) {ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);// 设置登录页面urlshiroFilterFactoryBean.setLoginUrl("/user/login");shiroFilterFactoryBean.setSuccessUrl("/user/index");shiroFilterFactoryBean.setUnauthorizedUrl("/user/unauthorized");// 注意此处使用的是LinkedHashMap是有顺序的,shiro会按从上到下的顺序匹配验证,匹配了就不再继续验证Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();filterChainDefinitionMap.put("/layer/**", "anon");// 静态资源放行filterChainDefinitionMap.put("/img/**", "anon");filterChainDefinitionMap.put("/jquery/**", "anon");// add.html页面放行filterChainDefinitionMap.put("/user/add", "authc");// update.html必须认证filterChainDefinitionMap.put("/user/update", "authc");// index.html必须认证filterChainDefinitionMap.put("/user/index", "user");// 设置授权,只有user:add权限的才能请求/user/add这个urlfilterChainDefinitionMap.put("/user/add", "perms[user:add]");filterChainDefinitionMap.put("/user/update", "perms[user:update]");shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);return shiroFilterFactoryBean;}// 实现记住我,所需要的配置@Beanpublic SimpleCookie simpleCookie() {// 这个参数是cookie的名称,对应前端的checkbox的name = rememberMeSimpleCookie simpleCookie = new SimpleCookie("rememberMe");simpleCookie.setHttpOnly(true);// 记住我cookie生效时间1小时,单位秒simpleCookie.setMaxAge(60 * 60);return simpleCookie;}// 实现记住我,所需要的配置@Beanpublic CookieRememberMeManager cookieRememberMeManager() {CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();cookieRememberMeManager.setCookie(simpleCookie());// rememberMe cookie加密的密钥 建议每个项目都不一样 默认AES算法 密钥长度(128 256 512 位)cookieRememberMeManager.setCipherKey(Base64.decode("4AvVhmFLUs0KTA3Kprsdag=="));return cookieRememberMeManager;}
}

login.html 登录页面

此时要拿到复选框 checkbox 是否被用户选中的状态值,选中为 true,未选中为 false,将这个状态值发生至后端登录接口

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>登录</title><link rel="shortcut icon" type="image/x-icon" th:href="@{/img/favicon.ico}"/>
</head>
<body>
<form action="" method="post"><p>账号:<label><input type="text" class="username" name="username"></label></p><p>密码:<label><input type="text" class="password" name="password"></label></p><p><label><input id="checkbox1" type="checkbox" name="rememberMe"></label>记住我</p><p><button type="button" class="loginBtn">登录</button></p>
</form>
</body>
<script type="text/javascript" th:src="@{/jquery/jquery-3.3.1.min.js}"></script>
<script type="text/javascript" th:src="@{/layer/layer.js}"></script><!--layui的弹出层-->
<script type="text/javascript">$(document).ready(function () {$('.loginBtn').on('click', function () { // 登录按钮const username = $('.username').val();const password = $('.password').val();const rememberMe = $("input[type='checkbox']").is(':checked');$.ajax({// 用户登录type: 'post',url: '/user/doLogin',dataType: 'json',data: ({'username': username,'password': password,'rememberMe': rememberMe}),success: function (resp) {console.log(resp);if (resp.code !== 200) {layer.msg(resp.message, function () {// layui的弹窗});} else if (resp.code === 200) {window.location.href = 'http://127.0.0.1:8080'+ resp.action;}},error: function () {// 此处添加错误处理layer.open({title: '提示信息',content: '后台访问错误,请联系管理员',skin: 'layui-layer-molv',icon: 0});}});});});
</script>
</html>

controller

@Controller
@RequestMapping(path = "/user")
@Slf4j
public class UserController {@GetMapping(path = "/login")public String login() {return "login";}@GetMapping(path = "/index")public String index() {return "index";}@GetMapping(path = "/add")public String add() {return "add";}@GetMapping(path = "/update")public String update() {return "update";}@GetMapping(path = "/unauthorized")public String unauthorized() {return "unauthorized";}/*** 用户登录** @param userVO* @param bindingResult* @return*/@PostMapping(path = "/doLogin")@ResponseBodypublic ResultMap doLogin(@NotNull @Valid UserVO userVO, @NotNull BindingResult bindingResult) {// ------参数校验------if (bindingResult.hasErrors()) {String message = Objects.requireNonNull(bindingResult.getFieldError()).getDefaultMessage();log.info("校验的message信息为:" + message);return new ResultMap().fail().message(message);}// 将用户名,密码交给shiroUsernamePasswordToken token = new UsernamePasswordToken(userVO.getUsername(), userVO.getPassword(), userVO.getRememberMe());String msg;try {// shiro帮我们匹配密码什么的,我们只需要把东西传给它,它会根据我们在UserRealm里认证方法设置的来验证Subject subject = SecurityUtils.getSubject();subject.login(token);return new ResultMap().success().action("/user/index");} catch (AuthenticationException e) {if (e instanceof IncorrectCredentialsException) {msg = "密码错误";} else if (e instanceof LockedAccountException) {msg = "用户被禁用";} else if (e instanceof UnknownAccountException) {msg = "用户不存在";} else {msg = "用户认证失败";}}return new ResultMap().error().message(msg);}/*** 用户退出登录* 添加记住我功能了,退出登录时,除了要当前的subject退出之外,还要删除用户浏览器上的Cookie信息** @return*/@GetMapping(path = "/logout")public String logout(HttpServletResponse response) {Subject subject = SecurityUtils.getSubject();if (subject.isAuthenticated()) {subject.logout();Cookie cookie = new Cookie("rememberMe", null);cookie.setMaxAge(0);response.addCookie(cookie);}return "login";}
}

UserVO

public class UserVO implements Serializable {@NotBlank(message = "账号不能为空")private String username;@NotEmpty(message = "密码不能为空")private String password;private Boolean rememberMe;// 省略set/get方法
}

测试

我们以账号 jack 为例进行登录,如下


进入首页页面如下,再次查看 Cookies 数据


我们这时关闭这个首页页面,在浏览器地址栏输入 http://127.0.0.1:8080/user/index 再次进入首页页面,会发现如上图一样,可以顺利访问,说明我们的记住我功能已经实现。这时,可以再次在浏览器地址栏输入 http://127.0.0.1:8080/user/add,进入 add.html 页面,如下


Cookies 的有效期内,当你关闭浏览器之后,再次进入 add.html 页面时,无需登录直接就可以访问了,说明记住我功能已经实现了。在浏览器地址栏输入 http://127.0.0.1:8080/user/update,进入 update.html 页面,如下


说明账号 jack 没有权限访问 update.html 页面,可以看控制台 sql 日志


源码:springboot-shiro

springboot整合shiro之实现记住我相关推荐

  1. springboot整合shiro和session的详细过程和自定义登录拦截器

    文章目录 1.shiro依赖 2.shiro配置 shiro过滤器配置: 关联自定义的其他管理器 自定义会话工厂: 3.登陆时记录用户信息 4.shiro一些工具类的学习 5.自定义登录拦截器 shi ...

  2. SpringBoot整合Shiro实现登录认证和授权CHCache

    文章目录 一. springboot实现普通登录 1 添加依赖 2 编写配置文件 3 新建实体类和mapper 4 编写业务层代码 5 编写控制器 6 编写启动类 7 编写登录页面和主页面 二. sp ...

  3. 补习系列(6)- springboot 整合 shiro 一指禅

    欢迎添加华为云小助手微信(微信号:HWCloud002 或 HWCloud003),输入关键字"加群",加入华为云线上技术讨论群:输入关键字"最新活动",获取华 ...

  4. SpringBoot整合Shiro实现权限控制,验证码

    本文介绍 SpringBoot 整合 shiro,相对于 Spring Security 而言,shiro 更加简单,没有那么复杂. 目前我的需求是一个博客系统,有用户和管理员两种角色.一个用户可能有 ...

  5. SpringBoot 整合Shiro 一指禅

    目标 了解ApacheShiro是什么,能做什么: 通过QuickStart 代码领会 Shiro的关键概念: 能基于SpringBoot 整合Shiro 实现URL安全访问: 掌握基于注解的方法,以 ...

  6. springboot整合shiro

    springboot整合shiro 导入依赖 <!-- shiro鉴权框架--> <dependency><groupId>org.apache.shiro< ...

  7. SpringBoot整合Shiro实现权限管理与登陆注册

    前言 Shiro解决了什么问题? 互联网无非就是一些用户C想要使用一些服务S的资源去完成某件事,S的资源不能说给谁用就给谁用,因此产生了权限的概念,即C必须有权限才能操作S的资源.S如何确定C就是C呢 ...

  8. springboot整合shiro(超详细,你想要的都在这了)

    Springboot整合Shiro 文章目录 pom依赖 前端页面(thymeleaf整合shiro) thymeleaf中shiro标签解释 数据库(整合mybatis) 理解shiro的几个组成部 ...

  9. 补习系列-SpringBoot 整合Shiro 一指禅

    目标 了解ApacheShiro是什么,能做什么: 通过QuickStart 代码领会 Shiro的关键概念: 能基于SpringBoot 整合Shiro 实现URL安全访问: 掌握基于注解的方法,以 ...

  10. 补习系列- springboot 整合 shiro 一指禅

    目标 了解ApacheShiro是什么,能做什么: 通过QuickStart 代码领会 Shiro的关键概念: 能基于SpringBoot 整合Shiro 实现URL安全访问: 掌握基于注解的方法,以 ...

最新文章

  1. 史上最难的一道Java面试题
  2. linux杂谈(二十):apache服务配置
  3. SQL 解决in的参数烦恼(经典,简洁,高效)
  4. 【修正】销售开票BAPI实例:BAPI_BILLINGDOC_CREATEMULTIPLE
  5. toj 4065 The Coco-Cola Store
  6. redux 思考以及源码解析
  7. java jdbc 工具_JDBC 工具类
  8. 学习前端开发,自学真的能成功?
  9. 基于html5 Canvas图表库 : ECharts
  10. Gradle依赖的统一管理
  11. 微信公众号模板消息配置和发送
  12. 【C++ STL学习笔记】C++ STL基础
  13. VS2010设计rdlc报表时找不到“报表数据”选项卡的解决方法
  14. JDK8安装时错误1335的解决
  15. VC加载jpeg, png图片的方法
  16. halcon学习和实践(第一个范例threshold.hdev)
  17. lap 加MySQL主从复制_LAP+mysql-主从+redis
  18. MacOS任意降级(完美教程)
  19. 如何架设一个属于自己的Discuz论坛
  20. linux卸载常用软件,Linux 下软件安装卸载常用方法

热门文章

  1. 自动驾驶1-5: 感知要求Requirements for Perception
  2. Mac OS 开启三指拖移,三指缩放,拖拽窗口,切换全面页面变成四指
  3. 鸿蒙手机开发者活动,华为 12 月16 日举行鸿蒙 2.0 手机开发者 Beta 活动
  4. Batch, Iteration,Epoch概念理解
  5. 数据是指在计算机科学中能够被,5. 数据在 计算机科学中 是指所有能输入到计算机并 被计算机程序处理的符号的总称。( )...
  6. 现代通信原理3.3:两个重要的信号处理模块-乘法器与滤波器
  7. 欠定线性系统与正则化
  8. 腾讯云服务器ftp部署及文件上传
  9. 透過 OpenNI / NITE 分析人體骨架(上)
  10. 【扩展KMP】【HDU 4333】Revolving Digits