前言
上一篇 文章我們完成了在 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之實現記住我內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!
原文鏈接:https://blog.csdn.net/weixin_38192427/article/details/120928810