一、需求分析

如图所示,一般网站的登录界面都会有一个 [记住我] 按钮,当你勾选它登录后,即使你关闭浏览器再次打开网站,也依然会处于登录状态,无须重复验证密码:

本文将详细介绍在 Sa-Token中,如何做到以下登录模式:

  • 记住我登录:登录后关闭浏览器,再次打开网站登录状态依然有效,无需重复登录。
  • 仅本次有效登录:登录后关闭浏览器,再次打开网站登录状态将失效,需要再次登录。
  • 七天免登录:为登录状态设定一个详细的有效期,在这个期限内无需重复登录,过了期限后需要再次登录。

Sa-Token 是一个轻量级 java 权限认证框架,主要解决登录认证、权限认证、单点登录、OAuth2、微服务网关鉴权 等一系列权限相关问题。

首先在项目中引入 Sa-Token 依赖:

<!-- Sa-Token 权限认证 -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot-starter</artifactId>
<version>1.34.0</version>
</dependency>

注:如果你使用的是 SpringBoot 3.x,只需要将 sa-token-spring-boot-starter 修改为 sa-token-spring-boot3-starter 即可。

二、在 Sa-Token 中实现记住我功能

Sa-Token的登录授权,默认就是[记住我]模式,为了实现[非记住我]模式,你需要在登录时如下设置:

// 设置登录账号id为10001,第二个参数指定是否为[记住我],当此值为false后,关闭浏览器后再次打开需要重新登录
StpUtil.login(10001, false);

那么,Sa-Token实现[记住我]的具体原理是?

三、实现原理

Cookie作为浏览器提供的默认会话跟踪机制,其生命周期有两种形式,分别是:

  • 临时Cookie:有效期为本次会话,只要关闭浏览器窗口,Cookie就会消失。
  • 持久Cookie:有效期为一个具体的时间,在时间未到期之前,即使用户关闭了浏览器Cookie也不会消失。

利用Cookie的此特性,我们便可以轻松实现 [记住我] 模式:

  • 勾选 [记住我] 按钮时:调用StpUtil.login(10001, true),在浏览器写入一个持久Cookie储存 Token,此时用户即使重启浏览器 Token 依然有效。
  • 不勾选 [记住我] 按钮时:调用StpUtil.login(10001, false),在浏览器写入一个临时Cookie储存 Token,此时用户在重启浏览器后 Token 便会消失,导致会话失效。

动态演示图:

四、前后端分离模式下如何实现[记住我]?

此时机智的你很快发现一个问题,Cookie虽好,却无法在前后端分离环境下使用,那是不是代表上述方案在APP、小程序等环境中无效?

准确的讲,答案是肯定的,任何基于Cookie的认证方案在前后端分离环境下都会失效(原因在于这些客户端默认没有实现Cookie功能),不过好在,这些客户端一般都提供了替代方案,

唯一遗憾的是,此场景中token的生命周期需要我们在前端手动控制:

以经典跨端框架 uni-app 为例,我们可以使用如下方式达到同样的效果:

// 使用本地存储保存token,达到 [持久Cookie] 的效果
uni.setStorageSync("satoken", "xxxx-xxxx-xxxx-xxxx-xxx"); // 使用globalData保存token,达到 [临时Cookie] 的效果
getApp().globalData.satoken = "xxxx-xxxx-xxxx-xxxx-xxx";

如果你决定在PC浏览器环境下进行前后端分离模式开发,那么更加简单:

// 使用 localStorage 保存token,达到 [持久Cookie] 的效果
localStorage.setItem("satoken", "xxxx-xxxx-xxxx-xxxx-xxx"); // 使用 sessionStorage 保存token,达到 [临时Cookie] 的效果
sessionStorage.setItem("satoken", "xxxx-xxxx-xxxx-xxxx-xxx");

Remember me, it's too easy!

五、登录时指定 Token 有效期

登录时不仅可以指定是否为[记住我]模式,还可以指定一个特定的时间作为 Token 有效时长,如下示例:

// 示例1:
// 指定token有效期(单位: 秒),如下所示token七天有效
StpUtil.login(10001, new SaLoginModel().setTimeout(60 * 60 * 24 * 7)); // ----------------------- 示例2:所有参数
// `SaLoginModel`为登录参数Model,其有诸多参数决定登录时的各种逻辑,例如:
StpUtil.login(10001, new SaLoginModel()
.setDevice("PC") // 此次登录的客户端设备类型, 用于[同端互斥登录]时指定此次登录的设备类型
.setIsLastingCookie(true) // 是否为持久Cookie(临时Cookie在浏览器关闭时会自动删除,持久Cookie在重新打开后依然存在)
.setTimeout(60 * 60 * 24 * 7) // 指定此次登录token的有效期, 单位:秒 (如未指定,自动取全局配置的 timeout 值)
.setToken("xxxx-xxxx-xxxx-xxxx") // 预定此次登录的生成的Token
.setIsWriteHeader(false) // 是否在登录后将 Token 写入到响应头
);

注:如果在登录时未指定 new SaLoginModel().setTimeout(604800) 那么框架将采用全局配置的 sa-token.timeout 值作为 Token 的有效期。

六、不同登录策略的代码对比

以下是三种登录策略的代码差异:

package com.pj.cases.up;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult; /**
* Sa-Token 记住我模式登录
*
* @author kong
* @since 2022-10-17
*/
@RestController
@RequestMapping("/RememberMe/")
public class RememberMeController { // 记住我登录 ---- http://localhost:8081/RememberMe/doLogin?name=zhang&pwd=123456
@RequestMapping("doLogin")
public SaResult doLogin(String name, String pwd) {
if("zhang".equals(name) && "123456".equals(pwd)) {
StpUtil.login(10001, true);
return SaResult.ok("登录成功");
}
return SaResult.error("登录失败");
} // 不记住我登录 ---- http://localhost:8081/RememberMe/doLogin2?name=zhang&pwd=123456
@RequestMapping("doLogin2")
public SaResult doLogin2(String name, String pwd) {
if("zhang".equals(name) && "123456".equals(pwd)) {
StpUtil.login(10001, false);
return SaResult.ok("登录成功");
}
return SaResult.error("登录失败");
} // 七天免登录 ---- http://localhost:8081/RememberMe/doLogin3?name=zhang&pwd=123456
@RequestMapping("doLogin3")
public SaResult doLogin3(String name, String pwd) {
if("zhang".equals(name) && "123456".equals(pwd)) {
StpUtil.login(10001, 60 * 60 * 24 * 7);
return SaResult.ok("登录成功");
}
return SaResult.error("登录失败");
} }

可依次访问注释中提供的测试链接,观察不同登录策略带来的会话有效期差异。


参考资料

使用 Sa-Token 实现 [记住我] 模式登录、七天免登录的更多相关文章

  1. 基于EasyNVR摄像机无插件直播流媒体服务器实现类似于单点登录功能的免登录直播功能

    提出问题 EasyNVR是一套摄像机无插件直播的流媒体服务器软件,他可以接入各种各样的摄像机,再经过转化统一输出无插件化直播的RTMP.HLS.HTTP-FLV流,同时,EasyNVR为了数据安全,提 ...

  2. axios token header response request http拦截器 axios实现登录、拦截、登出

    axios token header response request http拦截器 axios实现登录.拦截.登出 一个项目学会前端实现登录拦截 https://github.com/superm ...

  3. Shiro+SpringMVC 实现更安全的登录(加密匹配&登录失败超次数锁定帐号)

    原文:http://blog.csdn.net/wlwlwlwl015/article/details/48518003 前言 初学shiro,shiro提供了一系列安全相关的解决方案,根据官方的介绍 ...

  4. SpringBoot 整合 Shiro 密码登录与邮件验证码登录(多 Realm 认证)

    导入依赖(pom.xml)  <!--整合Shiro安全框架--> <dependency> <groupId>org.apache.shiro</group ...

  5. 用Abp实现两步验证(Two-Factor Authentication,2FA)登录(三):免登录验证

    @ 目录 原理 修改请求报文 配置JwtBearerOptions 生成Token 校验Token 修改认证EndPoint 修改前端 登录 登出 最终效果 项目地址 免登录验证是用户在首次两步验证通 ...

  6. 火车采集器 帝国CMS7.2免登录发布模块

    帝国cms7.2增加了金刚模式,登录发布有难度.免登录发布模块配合火车采集器,完美解决你遇到的问题. 免登录直接获取栏目列表 通过文件内设置密码免登录发布数据 帝国cms7.2免登陆文章发布接口使用说 ...

  7. 登录式与非登录式&交互式与非交互式shell及其环境初始化过程

    交互式shell和非交互式shell(interactive shell and non-interactive shell) 交互式模式就是在终端上执行,shell等待你的输入,并且立即执行你提交的 ...

  8. 登录失败。该登录名来自不受信任的域,不能与 Windows 身份验证一起使用

    登录失败.该登录名来自不受信任的域,不能与 Windows 身份验证一起使用 使用sever sql  远程连接数据库的时候遇到了这个问题,我用的是ADO.NET 实体数据模型,有web.config ...

  9. 交互式shell和非交互式shell、登录shell和非登录shell的区别

    交互式shell和非交互式shell.登录shell和非登录shell的区别.首先,这是两个不同的维度来划分的,一个是是否交互式,另一个是是否登录. 交互式shell和非交互式shell(intera ...

  10. SQL点滴11—重置win7登录密码影响SQL登录

    原文:SQL点滴11-重置win7登录密码影响SQL登录 2011-04-20  修改机器登录密码后不能登录SQL Server 今天发现一个很有趣的现象.公司的电脑每两个月就会提示重置登录密码,今天 ...

随机推荐

  1. AIGC时代:未来已来

    摘要:人工智能的快速发展使得我们进入了AIGC时代.AIGC时代的到来,将会带来巨大的机遇和挑战. 本文分享自华为云社区<GPT-4发布,AIGC时代的多模态还能走多远?系列之一: AIGC时代 ...

  2. python实现员工信息表

    学习python时,看到的一个题目第一次写博客, 有误的地方还请大佬们指正,十分感谢~要求如下'''文件存储格式如下:id,name,age,phone,job(这行不需要写)1,alice,22,1 ...

  3. 逍遥自在学C语言 | 逻辑运算符

    前言 一.人物简介 第一位闪亮登场,有请今后会一直教我们C语言的老师 -- 自在. 第二位上场的是和我们一起学习的小白程序猿 -- 逍遥. 二.构成和表示方式 逻辑运算符是用来比较和操作布尔值的运算符 ...

  4. [PKM] 个人知识管理

    1 个人知识管理的需求 1.1 背景 随着信息大爆炸,碎片化的知识越来越多,原来中小学阶段在学校中习得的.传统的.基于纸质笔记的知识管理方式已不能满足当前的诉求. 传统的基于纸质笔记的知识管理方式 工 ...

  5. [JavaScript]Base64 ←→ 图像

    1 Base64 → 图像 [demo1] document.getElementById('img').setAttribute( 'src', 'data:image/png;base64,iVB ...

  6. 五月八号java基础知识点

    1.对于容器中元素进行访问时,经常需要按照某种次序对容器中的每个元素访问且仅访问 一次,这就是遍历,也称为迭代.2.遍历是指从容器中获得当前元素的后续元素.对元素的遍历有很多种:第一种就是foreac ...

  7. Redis缓存高可用集群

    作者:京东零售 王雷 1.Redis集群方案比较 • 哨兵模式 在redis3.0以前的版本要实现集群一般是借助哨兵sentinel工具来监控master节点的状态,如果master节点异常,则会做主 ...

  8. Docker构建镜像踩坑日记

    从Github上拉取python项目后,运行dockerfile构建镜像失败,一步步查找原因 主要原因就是国内下载各种依赖超时,以下提供pip.apt.pipenv镜像解决方案 pip更换国内镜像 这 ...

  9. NLP入门1——李宏毅网课笔记

    近日因为项目需要,开始恶补预习NLP的相关知识.以前也看过两本相关书籍,但是都十分浅显.这次准备详细的学一下并记录. 李宏毅老师的网课是 Deep Learning for Human Languag ...

  10. 分享Zeal的全套离线文档

    鉴于Zeal自身的下载速度... 为了方便大家,现在把我自己下载好的Zeal离线文档全部分享出来 百度网盘链接:https://pan.baidu.com/s/19WeEWij3evnuMWhzbHu ...