springboot整合shiro实现记住我功能

前言

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

springboot 整合 shiro 之实现记住我

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

配置类 ShiroConfig

完整的代码如下

@Configuration
public class ShiroConfig {

    /**
     * 安全管理器
     *
     * @param userRealm userRealm
     * @return defaultWebSecurityManager
     */
    @Bean
    public DefaultWebSecurityManager getDefaultWebSecurityManager(UserRealm userRealm) {
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
        defaultWebSecurityManager.setRealm(userRealm);
        // 实现记住我,所需要的配置
        defaultWebSecurityManager.setRememberMeManager(cookieRememberMeManager());
        return defaultWebSecurityManager;
    }

    /**
     * thymeleaf模板引擎中使用shiro标签时,要用到
     *
     * @return
     */
    @Bean
    public ShiroDialect getShiroDialect() {
        return new ShiroDialect();
    }

    @Bean
    public ShiroFilterFactoryBean shiroFilter(DefaultWebSecurityManager defaultWebSecurityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
        // 设置登录页面url
        shiroFilterFactoryBean.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这个url
        filterChainDefinitionMap.put("/user/add", "perms[user:add]");
        filterChainDefinitionMap.put("/user/update", "perms[user:update]");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }

	// 实现记住我,所需要的配置
    @Bean
    public SimpleCookie simpleCookie() {
        // 这个参数是cookie的名称,对应前端的checkbox的name = rememberMe
        SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
        simpleCookie.setHttpOnly(true);
        // 记住我cookie生效时间1小时,单位秒
        simpleCookie.setMaxAge(60 * 60);
        return simpleCookie;
    }

	// 实现记住我,所需要的配置
    @Bean
    public 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")
    @ResponseBody
    public 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);
        }
        // 将用户名,密码交给shiro
        UsernamePasswordToken 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之实现记住我的文章就介绍到这了,更多相关springboot整合shiro之实现记住我内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • shiro 与 SpringMVC的整合完美示例

    想要整合Shiro和springmvc,在网上找了很多例子,感觉都有一点复杂.所以就自己写了一个最简单整合项目,记录在这里以备后面查看. 这个例子包含如下三个部分: 1.简单的页面 2.shiro配置 3.springmvc配置 shiro可以直接和spring整合,但是这样需要单独配置spring用于整合shiro,在配置springmvc.配置文件看起来乱七八糟的.所以这里就shiro不采用spring来管理.因此这里的整合类似 shiro + servlet + springmvc.这样配

  • Java Apache Shiro安全框架快速开发详解流程

    目录 一.Shiro简介: shiro功能: Shiro架构(外部) Shiro架构(内部) 二.快速入门 1.拷贝案例 2.分析代码 三.SpringBoot 集成 Shiro 1.编写测试环境 2.使用 1.登录拦截 2.用户认证 四.Shiro整合Mybatis 五.实现请求授权 六.Shiro整合Thymeleaf 一.Shiro简介: Apache Shiro是一个Java的安全(权限)框架. Shiro 可以非常容易的开发出足够好的应用,其不仅可以用在JavaSE环境,也可以用在Ja

  • 详解springboot shiro jwt实现权限管理

    springboot + shiro + jwt (详情解析+代码实现)加密接口 设置权限 首先需要把shiro的几个配置类给下载好(我已经把需要的配置类给放到了github和网盘之中) 先讲完各个配置类的作用,后面讲具体流程 ShiroConfig.java 类主要是设置了过滤器 和shiro自己的session,假如这个类没有放行就只有token才能访问后端接口 UserRealm.java 类主要是检测用户权限和授予权限,对用户名的验证 JWTFilter.java 类主要是防止别人访问你

  • springboot整合shiro的过程详解

    目录 什么是 Shiro Shiro 架构 Shiro 架构图 Shiro 工作原理 Shiro 详细架构图 springboot 整合 shiro springboot 整合 shiro 思路 项目搭建 主要依赖 数据库表设计 实体类 自定义 Realm shiro 的配置类 ShiroFilterFactoryBean 过滤器链配置中的 url 匹配规则 ShiroFilterFactoryBean 过滤器 ShiroFilterFactoryBean 过滤器分类 前端页面 登录页面 log

  • spring-shiro权限控制realm实战教程

    目录 spring-shiro权限控制realm 用户与角色实体 Realm类 Shiro 配置类 控制器 Service shiro权限不生效原因分析 shiro遇到的坑 问题原因:权限标签定义问题 spring-shiro权限控制realm 用户与角色实体 Role.java @Data @Entity public class Role { @Id @GeneratedValue private Integer id; private Long userId; private String

  • springboot整合shiro之thymeleaf使用shiro标签的方法

    thymeleaf介绍 简单说, Thymeleaf 是一个跟 Velocity.FreeMarker 类似的模板引擎,它可以完全替代 JSP .相较与其他的模板引擎,它有如下三个极吸引人的特点: 1.Thymeleaf 在有网络和无网络的环境下皆可运行,即它可以让美工在浏览器查看页面的静态效果,也可以让程序员在服务器查看带数据的动态页面效果.这是由于它支持 html 原型,然后在 html 标签里增加额外的属性来达到模板+数据的展示方式.浏览器解释 html 时会忽略未定义的标签属性,所以 t

  • springboot整合shiro实现记住我功能

    前言 上一篇文章我们完成了在 thymeleaf 模板引擎中使用 shiro 标签,也就是根据不同的用户身份信息,前端页面来显示不同的页面内容.本篇文章我们来完成在登录页面的记住我的功能 springboot 整合 shiro 之实现记住我 项目依然使用 springboot整合shiro这个项目,稍稍改动即可完成记住我的功能 配置类 ShiroConfig 完整的代码如下 @Configuration public class ShiroConfig { /** * 安全管理器 * * @pa

  • springboot整合shiro多验证登录功能的实现(账号密码登录和使用手机验证码登录)

    1. 首先新建一个shiroConfig shiro的配置类,代码如下: @Configuration public class SpringShiroConfig { /** * @param realms 这儿使用接口集合是为了实现多验证登录时使用的 * @return */ @Bean public SecurityManager securityManager(Collection<Realm> realms) { DefaultWebSecurityManager sManager

  • SpringBoot 整合 Shiro 密码登录与邮件验证码登录功能(多 Realm 认证)

    导入依赖(pom.xml) <!--整合Shiro安全框架--> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.4.0</version> </dependency> <!--集成jwt实现token认证--> <dependency

  • springboot整合Shiro的步骤

    1.创建一个springboot项目 选中web和thymeleaf 1.1新建index.html <!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head>     <meta charset="UTF-8">     <title>Title</title> </head&

  • SpringBoot 整合 Shiro 密码登录的实现代码

    导入依赖(pom.xml) <!--整合Shiro安全框架--> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.4.0</version> </dependency> <!--集成jwt实现token认证--> <dependency

  • Java安全框架——Shiro的使用详解(附springboot整合Shiro的demo)

    Shiro简介 Apache Shiro是一个强大且易用的Java安全框架,执行身份验证.授权.密码和会话管理 三个核心组件:Subject, SecurityManager 和 Realms Subject代表了当前用户的安全操作 SecurityManager管理所有用户的安全操作,是Shiro框架的核心,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务. Realm充当了Shiro与应用安全数据间的"桥梁"或者"连接器&q

  • springboot整合Shiro

    目录 什么是Shiro Shiro的三大核心概念 Shiro功能介绍 Springboot整合Shiro 导入依赖 javaConfig Realm Controller Shiro整合thymeleaf 导入依赖 HTML页面命名空间 使用举例 总结 什么是Shiro Apache Shiro是一个功能强大且易于使用的Java安全框架,它执行身份验证.授权.加密和会话管理.借助Shiro易于理解的API,您可以快速轻松地保护任何应用程序-从最小的移动应用程序到最大的web和企业应用程序. Sh

  • 详解Java springboot 整合Shiro框架

    目录 Shiro介绍 Springboot整合Shiro Shiro整合Thymeleaf 总结 Shiro介绍 Shiro是一款安全框架,主要的三个类Subject.SecurityManager.Realm Subject:表示当前用户 SecurityManager:安全管理器,即所有与安全有关的操作都会与SecurityManager交互:且其管理着所有Subject:可以看出它是Shiro的核心,它负责与Shiro的其他组件进行交互,它相当于SpringMVC中DispatcherSe

随机推荐