软件编程
位置:首页>> 软件编程>> java编程>> springboot整合shiro实现记住我功能

springboot整合shiro实现记住我功能

作者:桐花思雨  发布时间:2023-07-29 20:21:34 

标签: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 为例进行登录,如下

springboot整合shiro实现记住我功能

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

springboot整合shiro实现记住我功能

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

springboot整合shiro实现记住我功能

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

springboot整合shiro实现记住我功能

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

springboot整合shiro实现记住我功能

源码:springboot-shiro

来源:https://blog.csdn.net/weixin_38192427/article/details/120928810

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com