Springboot实现remember-me记住我功能

本文介绍了Web系统中常见的记住我(remeber-me)功能,详细解释了其实现原理和流程,并通过一个SpringBoot应用实例展示了如何创建记住我功能。用户在登录时勾选记住我,系统会在cookie中存储认证信息,下次访问时若session失效,仍能从cookie中恢复用户信息,实现免登录。退出时则清除cookie和session。
摘要由CSDN通过智能技术生成

1.什么是remeber-me?

remeber-me即记住我功能,是我们在登录web系统时的常见勾选项。当我们登录一个web系统时除了输入常规的用户名、密码后还可以勾选记住我选项(假设该系统提供了该选项),此时假设用户名、密码输入正确那么系统将会在客户浏览器cookie中记录用户登录相关认证相关信息。实现的效果就是当我们下次再次访问该网站某些页面时无需再次登录。

在这里插入图片描述

2.rember-me实现原理

2.1 登录过程中记住我流程:

在这里插入图片描述

2.2 直接访问系统目标页,服务端验证流程:

在这里插入图片描述

2.3 退出流程

删除cookie,销毁session。

3.使用springboot实现步骤

本文为了快速演示记住我功能将采取服务端硬编码方式代替数据库存储,表达的原理一致就Ok。

只列出关键部分代码,详细请看文章结尾源码链接查看完整代码。

3.1 创建用户模型

@Data
public class SysUser {
    private String username;
    private String password;
    private Integer rememberMe;
}

3.2 创建登录控制器

@Controller
@Slf4j
public class LoginController {
    @RequestMapping("/login")
    public String loginPage(){
        return "login";
    }

    @RequestMapping("/index")
    public String index(){
        return "index";
    }

    @PostMapping("/dologin")
    public String login(SysUser user,
                        HttpServletRequest request,
                        HttpServletResponse response,
                        Model model){
        // 判断用户名密码
        if(!("admin".equals(user.getUsername()) && "admin".equals(user.getPassword()))){
            return "redirect:login";
        }

        // 认证成功,向session中添加用户信息
        HttpSession session = request.getSession();
        session.setAttribute("user",user);

        // 判断是否勾选了记住我
        if(user.getRememberMe()!=null){
            // 为了演示方便token写死,为用户名:admin的base64编码
            Cookie cookie = new Cookie("boot_rememberMe", "YWRtaW4=");
            // 为了演示设置cookie过期时间为30s
            cookie.setMaxAge(30);
            response.addCookie(cookie);
        }

        return "redirect:index";
    }

    @GetMapping("/logout")
    public String logout(HttpServletRequest request, HttpServletResponse response){
        HttpSession session = request.getSession();
        if (null == session || session.getAttribute("user") == null) {
            return "login";
        }
        session.invalidate();
        Cookie[] cookies = request.getCookies();
        if (ObjectUtils.isEmpty(cookies)) {

        } else {
            for (Cookie cookie : cookies) {
                String name = cookie.getName();
                if (name.equals("boot_rememberMe")) {
                    cookie.setMaxAge(0);
                    response.addCookie(cookie);
                }
            }
        }

        return "login";

    }
}

3.3 创建RememberFilter

@Slf4j
@Component
public class RememberFilter implements Filter {
    private String[] noFilterArray=new String[]{"/login","/dologin"};

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
        List<String> noFilterList= Arrays.asList(noFilterArray);
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse res = (HttpServletResponse) response;
        String requestURI = req.getRequestURI();
        requestURI = requestURI.substring(requestURI.lastIndexOf("/"));
        // 判断是否为不需要过滤请求
        if (noFilterList.contains(requestURI)) {
            filterChain.doFilter(request,response);
        }else{
            HttpSession session = req.getSession();
            if (null==session||session.getAttribute("user")==null) {
                Cookie[] cookies = req.getCookies();
                if (ObjectUtils.isEmpty(cookies)) {
                    ((HttpServletResponse) response).sendRedirect(req.getContextPath()+"/login");
                    return;
                } else {
                    SysUser user = null;
                    for(Cookie cookie:cookies){
                        String name = cookie.getName();
                        if (name.equals("boot_rememberMe")) {
                            String value = cookie.getValue();
                            // 演示采用硬编码,实际需要和数据库中token比较
                            if (!value.equals("YWRtaW4=")) {
                                Cookie cookie1=new Cookie("boot_rememberMe",null);
                                cookie1.setMaxAge(0);
                                res.addCookie(cookie1);
                            }else{
                                user = new SysUser();
                                user.setUsername("admin");
                                user.setPassword("admin");
                                user.setRememberMe(1);
                                session.setAttribute("user", user);
                                log.info("从cookie中获取user放入session");
                            }
                        }
                    }
                    if(user==null){
                        ((HttpServletResponse) response).sendRedirect(req.getContextPath()+"/login");
                        return;
                    }
                }
            }
            filterChain.doFilter(request,response);
        }

    }
}

3.4 创建登录页

<form action="/dologin" method="post" th:action="@{/dologin}">
        <div class="title">
            <h1>后台管理系统</h1>
        </div>
        <div class="form-item">
            <label for="username">用户名:</label>
            <input type="text" id="username" name="username" />
        </div>
        <div class="form-item">
            <label for="password">密码:</label>
            <input type="text" id="password" name="password" />
        </div>
        <div class="form-item">
            <input type="checkbox" id="rememberMe" name="rememberMe" value="1"/>记住我
            <input type="checkbox" name="rememberMe" hidden="hidden">
        </div>
        <div class="form-item">
            <button type="submit" id="submit" class="btn btn-primary">
                登录
            </button>
        </div>
    </form>

3.5 创建首页

<body>
    欢迎,<span th:text="${session.user.username}"></span>
    <a href="" th:href="@{/logout}">退出</a>
</body>

4.测试

输入地址:localhost:9000/login,用户名:admin,密码:admin

4.1 不勾选记住我

不勾选就是简单的登录退出功能。

4.2 勾选记住我

  • 成功登陆后,关闭浏览器
  • 30s内再次打开浏览器输入首页地址发现可以直接访问
  • 30s后再次访问首页发现cookie失效直接跳转到登录页
  • 退出后cookie失效,无法再次访问首页

4.3 相关截图

在这里插入图片描述
在这里插入图片描述

  • 首页
    在这里插入图片描述

5.项目代码

https://gitee.com/indexman/boot_rememberme/tree/master/

Spring Security提供了Remember-me功能来让用户在下次访问时无需重新登录。要启用Remember-me功能,可以按照以下步骤进行配置: 1. 在Spring Security配置文件中启用Remember-me功能,例如: ``` http .rememberMe() .key("remember-me-key") .rememberMeParameter("remember-me") .tokenValiditySeconds(86400) .userDetailsService(userDetailsService); ``` 其中,key是用来加密Remember-me cookie的密钥,rememberMeParameter是用来接收Remember-me cookie的请求参数,tokenValiditySeconds是Remember-me cookie的有效期,userDetailsService是用来根据用户名获取用户信息的服务。 2. 在登录页面中添加Remember-me的复选框,例如: ``` <input type="checkbox" name="remember-me" value="true" /> Remember me ``` 3. 在登录成功后生成Remember-me cookie,例如: ``` @RequestMapping(value = "/login", method = RequestMethod.POST) public String login(@RequestParam("username") String username, @RequestParam("password") String password, @RequestParam(value = "remember-me", required = false) boolean rememberMe, HttpServletResponse response) { // 验证用户名和密码 // ... // 生成Remember-me cookie if (rememberMe) { TokenBasedRememberMeServices rememberMeServices = new TokenBasedRememberMeServices("remember-me-key", userDetailsService); rememberMeServices.setTokenValiditySeconds(86400); rememberMeServices.setAlwaysRemember(true); rememberMeServices.loginSuccess(request, response, authentication); } // ... } ``` 其中,如果用户勾选了Remember-me复选框,则调用TokenBasedRememberMeServices的loginSuccess方法生成Remember-me cookie。 4. 在下次访问时验证Remember-me cookie,例如: ``` http .csrf().disable() .authorizeRequests() .antMatchers("/admin/**").hasRole("ADMIN") .antMatchers("/user/**").hasAnyRole("USER", "ADMIN") .anyRequest().authenticated() .and() .formLogin() .loginPage("/login") .permitAll() .and() .rememberMe() .key("remember-me-key") .rememberMeParameter("remember-me") .tokenValiditySeconds(86400) .userDetailsService(userDetailsService); ``` 其中,Remember-me cookie会在每次请求时被自动验证,如果验证通过,则用户会被认为已经登录。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值