Spring 整合Shiro:记住我
1、登录方法
/** * 执行登录操作 * * @param username * @param password * @param rememberMe * @param model * @return */ @Log("登录") @RequestMapping("/login") String login(String username, String password, Boolean rememberMe, Model model) { //判断用户名和密码为空 if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) { model.addAttribute("msg", "用户名和密码不能为空!"); return "login.html"; } // shiro登录步骤 // 1、获取subject对象 Subject subject = SecurityUtils.getSubject(); // 2、封装对象 UsernamePasswordToken token = new UsernamePasswordToken(username, password); System.out.println(token.toString()); // 3、执行登录(失败会报异常,需捕获异常) // 实际开发中,用户名和密码错误,不给出明确提示 try { // 设置是否记住我 rememberMe = rememberMe == null ? false : rememberMe; // 设置记住我 token.setRememberMe(rememberMe);
// 登录 subject.login(token); // 这样url会改变为index_v1,不然还会是login return "redirect:/index_v1"; } catch (UnknownAccountException e) {//账号不存在 model.addAttribute("msg", "用户名不存在!"); return "/login"; } catch (LockedAccountException e) {//账户锁定 model.addAttribute("msg", "账户被锁定!"); return "/login"; } catch (IncorrectCredentialsException e) {//密码错误 model.addAttribute("msg", "密码错误!"); return "/login"; } }
2、ShiroConfig
/** * Copyright (C), 2018-2018, 谪仙科技有限公司 * FileName ShiroConfig * Author wangzhiguo * Date 2018-12-25 2:49 * Description Shiro配置 * History * <author> <time> <version> <desc> * wangzhiguo 2018-12-25 版本号 描述 */ package com.itgeek.config.shiro.config; import com.itgeek.config.shiro.realm.Myrealm; import org.apache.shiro.codec.Base64; import org.apache.shiro.session.mgt.SessionManager; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.CookieRememberMeManager; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.apache.shiro.web.servlet.SimpleCookie; import org.apache.shiro.web.session.mgt.DefaultWebSessionManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.LinkedHashMap; import java.util.Map; /** * 〈功能描述〉 * Shiro配置 * <p> * <p> * 系统启动,执行顺序 * realm -- > securityManager -- > filter * * @author wangzhiguo * @date 2018-12-25 * @since 1.0.0 */ @Configuration public class ShiroConfig { /** * shiro核心filter * * @return */ @Bean() public ShiroFilterFactoryBean getShiroFilterFactoryBean() { System.out.println("Shiro过滤器"); ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); // 设置SecurityManager(必须) shiroFilterFactoryBean.setSecurityManager(securityManager()); /** * shiro常用过滤器 * anon:无需认证 * authc:必须认证 * user:如果使用rememberMe功能可以直接访问 * perms:必须得到资源权限可以访问 * role:必须得到角色权限可以访问 */ // LinkedHashMap 可以保持顺序 Map<String, String> filterMap = new LinkedHashMap<>(); // 1、认证 filterMap.put("/", "anon"); filterMap.put("/index", "anon"); filterMap.put("/toLogin", "anon"); filterMap.put("/login", "anon"); // 2、资源权限 filterMap.put("/sys/add", "perms[user:edit]"); // 3、角色权限 // 所有请求都要认证 // filterMap.put("/**", "authc"); // 认证或记住我都可以登录 filterMap.put("/**", "user"); // 未授权 shiroFilterFactoryBean.setUnauthorizedUrl("/noAuth"); // 设置跳转的登录页 shiroFilterFactoryBean.setLoginUrl("/toLogin"); // 设置登录成功的页面 shiroFilterFactoryBean.setSuccessUrl("/index_v1"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap); return shiroFilterFactoryBean; } /** * 安全管理器 * 缓存注入在这 * * @return */ @Bean() public DefaultWebSecurityManager securityManager() { System.out.println("Shiro安全管理器"); DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); // 设置realm securityManager.setRealm(myrealm()); // session会话 // securityManager.setSessionManager(sessionManager()); // 设置记住我 securityManager.setRememberMeManager(rememberMeManager()); return securityManager; } /** * realm:自定义的认证和授权逻辑 * * @return */ @Bean() public Myrealm myrealm() { System.out.println("自定义Realm"); return new Myrealm(); } /** * 记住我 * * @return */ @Bean public CookieRememberMeManager rememberMeManager() { System.out.println("记住我:rememberMe"); CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager(); cookieRememberMeManager.setCookie(rememberMeCookie()); //这个地方有点坑,不是所有的base64编码都可以用,长度过大过小都不行,没搞明白,官网给出的要么0x开头十六进制,要么base64 cookieRememberMeManager.setCipherKey(Base64.decode("4AvVhmFLUs0KTA3Kprsdag==")); return cookieRememberMeManager; } /** * Cookie管理 * 创建记住我cookie * * @return */ @Bean public SimpleCookie rememberMeCookie() { System.out.println("rememberMeCookie"); SimpleCookie cookie = new SimpleCookie("rememberMe"); cookie.setHttpOnly(true); // 声明周期 cookie.setMaxAge(1 * 60 * 60); return cookie; } }
3、登录页面
<form action="/login" method="post"> <span style="color: red" th:text="${msg}"></span> <br> 姓名<input type="text" name="username"> <br> 密码<input type="password" name="password"> <br> 记住我<input type="checkbox" checked="checked" name="rememberMe"> <br> <button type="submit">登录</button> </form>
4、登录(记住我),会生成rememberMe CookIe
不记住我:rememberMe Cookie 不会生成
注销(SHiro:/logout)也会清除rememberMe Cookie