springboot整合shiro-配置记住我(四)

原文 : https://blog.csdn.net/qq_34021712/article/details/80306442

记住我功能在各各网站是比较常见的,实现起来也都差不多,主要就是利用cookie来实现,而shiro对记住我功能的实现也是比较简单的,只需要几步即可。
Shiro提供了记住我(RememberMe)的功能,比如访问一些网站时,关闭了浏览器下次再打开时还是能记住你是谁,下次访问时无需再登录即可访问,基本流程如下:
(1)、首先在登录页面选中RememberMe然后登录成功;如果是浏览器登录,一般会把RememberMe的Cookie写到客户端并保存下来;
(2)、关闭浏览器再重新打开;会发现浏览器还是记住你的;
(3)、访问一般的网页服务器端还是知道你是谁,且能正常访问;

Shiro配置记住我步骤:

在ShiroConfig中添加以下Bean

记住我cookie
/**
 * cookie对象;会话Cookie模板 ,默认为: JSESSIONID 问题: 与SERVLET容器名冲突,重新定义为sid或rememberMe,自定义
 * @return
 */
@Bean
public SimpleCookie rememberMeCookie(){
    //这个参数是cookie的名称,对应前端的checkbox的name = rememberMe
    SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
    //setcookie的httponly属性如果设为true的话,会增加对xss防护的安全系数。它有以下特点:

    //setcookie()的第七个参数
    //设为true后,只能通过http访问,javascript无法访问
    //防止xss读取cookie
    simpleCookie.setHttpOnly(true);
    simpleCookie.setPath("/");
    //<!-- 记住我cookie生效时间30天 ,单位秒;-->
    simpleCookie.setMaxAge(2592000);
    return simpleCookie;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
记住我管理器
/**
 * cookie管理对象;记住我功能,rememberMe管理器
 * @return
 */
@Bean
public CookieRememberMeManager rememberMeManager(){
    CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
    cookieRememberMeManager.setCookie(rememberMeCookie());
    //rememberMe cookie加密的密钥 建议每个项目都不一样 默认AES算法 密钥长度(128 256 512 位)
    cookieRememberMeManager.setCipherKey(Base64.decode("4AvVhmFLUs0KTA3Kprsdag=="));
    return cookieRememberMeManager;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
记住我Filter
/**
 * FormAuthenticationFilter 过滤器 过滤记住我
 * @return
 */
@Bean
public FormAuthenticationFilter formAuthenticationFilter(){
    FormAuthenticationFilter formAuthenticationFilter = new FormAuthenticationFilter();
    //对应前端的checkbox的name = rememberMe
    formAuthenticationFilter.setRememberMeParam("rememberMe");
    return formAuthenticationFilter;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
在SecurityManager中打开记住我,之前是注释掉的
/**
 * 配置核心安全事务管理器
 * @param shiroRealm
 * @return
 */
@Bean(name="securityManager")
public SecurityManager securityManager(@Qualifier("shiroRealm") ShiroRealm shiroRealm) {
    DefaultWebSecurityManager securityManager =  new DefaultWebSecurityManager();
    //设置自定义realm.
    securityManager.setRealm(shiroRealm);
    //配置记住我 参考博客:
    securityManager.setRememberMeManager(rememberMeManager());

    //配置 redis缓存管理器 参考博客:
    //securityManager.setCacheManager(getEhCacheManager());

    //配置自定义session管理,使用redis 参考博客:
    //securityManager.setSessionManager(sessionManager());

    return securityManager;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
修改shirFilter中拦截请求的规则,将/**从authc 改为user
@Bean(name = "shirFilter")
public ShiroFilterFactoryBean shiroFilter(@Qualifier("securityManager") SecurityManager securityManager) {

    ......

    // 配置访问权限 必须是LinkedHashMap,因为它必须保证有序
    // 过滤链定义,从上向下顺序执行,一般将 /**放在最为下边 --> : 这是一个坑,一不小心代码就不好使了
    LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();

    //其他资源都需要认证  authc 表示需要认证才能进行访问 user表示配置记住我或认证通过可以访问的地址
    filterChainDefinitionMap.put("/**", "user");

    ......


    return shiroFilterFactoryBean;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
更改LoginController中login方法

接受前台记住我参数,然后传给usernamePasswordToken,将之前的那行注释掉。

@RequestMapping(value = "/login",method = RequestMethod.POST)
public String loginUser(HttpServletRequest request, String username, String password,boolean rememberMe, Model model, HttpSession session) {

    //对密码进行加密
    //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);
        User user=(User) subject.getPrincipal();
        //更新用户登录时间,也可以在ShiroRealm里面做
        session.setAttribute("user", user);
        model.addAttribute("user",user);
        return "index";
    } catch(Exception e) {
        //登录失败从request中获取shiro处理的异常信息 shiroLoginFailure:就是shiro异常类的全类名
        String exception = (String) request.getAttribute("shiroLoginFailure");
        model.addAttribute("msg",e.getMessage());
        //返回登录页面
        return "login";
    }
}
  • 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
UserInfo实体类实现序列化

UserInfo实体类必须实现序列化接口,否则报序列化异常。因为RememberMe会将用户信息加密然后以Cookie保存。

前台页面添加记住我复选框
<!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="checkbox" name="rememberMe" />记住我<br/>
    <input type="submit" value="提交"/>
</form>
</body>
</html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

进行测试

上面的过程已经配置完成,现在进行测试,重启项目,使用admin登录,然后访问:http://localhost:9090/userInfo/view会跳转到登录页面,登录之后退出浏览器,再次点开访问刚才的页面,可以访问。

浏览器cookie查看

重新访问可以访问,我们可以使用浏览器自带的调试功能查看浏览器保存的cookie是什么样的,如下:
springboot整合shiro-配置记住我(四)

rememberMe 大概内容如下:

Ir72ULwc24d/waGzOIYpBUpEakqqezDnuIRr91Lc2UvUVEeln2C+mDICIe338+vZIycabYe0KWuAY7x4PuklO9KeiUu15sHOPJO4bkpYVd4HcoITCi54+KqQhl/47lOO7ucM0BVWkDhEQr3CaFw9lGESg0dZiVrFTDgrwjPBXn0JJzHH7Bs/
itW1IfhqzCJZjUH5nU7J+kG7NQ40f1f2HpZHH0Mlg5zTjCT0JK8Zib2TRd74rYWNnFxtz/
u2C1BrSYGvwdNcI0oouY3CjpJ18PmI6W4MZC4lWzXBPi9OEv8AcHhVRVaCvPrGl52goZr1iOXcM2eOaJoVe5FyBnaD4EWjwFYIZMUPEGXHCsbWsyKp00mQT+/7rQRxd3rq/
v6r+H291CYSq1NfdRDetozMjSVtAMpvceCPbH8tfeHTlbb7B/g1xrsw0BxvsSAWdZm9t6yWP4NREe9bxaPmbmRMklssHLwG63tBgBS2/SOvACeEr0cLJmYIub+3LhVfRwvgjQpW+cRTBA/SnOIPMAw1/8A63BYpgV/9HwckafxKLLn1
0mcSZ7t4ZY8HB+L7ataFZC3aL6s49gbHUhood8yFRreS1yrEqqiucecd+vZFPn4GxHAyayeyI7VXvoaUa8AU6WQ16TBlDXvftOcQQ7maBetfitl7CtZ5pBHDU5YxF6sM5mSH+hIoB+l1o9NLlxnrQg6qAKWGeNao+1lXj/
OjNZu4IZfpJrfkd+NvgHaSyfvVbo8eiedgScATiJ2nzP6NVydWs370LVRazN7LuGcUAz8pdOrlCtwshY/2/jFQNRsUpzuB3Ml1AOrFCVnhyz7bvXqS3+lzQsTsHN370sf35D0dozVEW8wreWG4IfUKydrioUjyeChVga8w5Ir7L46UW
7K1M33gEdpUL1tkda6435EsaCfywRKDy26O4LkcWTLAmDLhvEOGXkxp3guQaZb8VTMTQA7XNU2pzlAdxPJ4JeLAyxExFOS956eGZKbB9qum2+ROc++nb34oAl/9yo0b9eHgh0yZvyWSfi4QVbgrYQ==
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

其实是将用户信息加密后放到前台的(包含密码),在项目中user对象信息过于庞大,不能全部存入Cookie,Cookie对长度有一定的限制。

上一篇:Shiro<=1.2.4反序列化


下一篇:spring security 学习三-rememberMe