一、需求分析

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

本文将详细介绍在 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. java-树形结构数据

    在我们实际开发中会接触到树形结构,根节点子节点, 然后添加数据构成了我们的树形结构, 在Java后台利用递归思路进行构建树形结构数据,返回给前端,能以下拉菜单等形式进行展示, 以某市行政区为例 后端需 ...

  2. CentOS 9 开局配置

    CentOS 9 开局配置 CentOS 9 发布有几年了,一直没有尝试使用,CentOS 9 有一些变动. 查看系统基础信息 # 查看系统基础信息 [root@chenby ~]# neofetch ...

  3. QtDesigner第一个程序

    用QTDesigner设计界面简单多了,而且更加直观.先看下效果图,是不是比我们用代码写的布局要美观多了 制作.ui界面 (1).打开Pycharm的界面设计工具QTDsigner Pycharm-& ...

  4. 8.redis存储token以及springboot整合Jwt

    1.总结: 昨天主要是下载安装和使用redis去存储token,但在创建redis的新建的时候出现了host异常,原因是没有将服务中的进程关掉,再重新打开redis的server,再打开cli: 回顾 ...

  5. day07-OpenFeign-服务调用

    SpringCloud OpenFeign-服务调用 1.OpenFeign介绍 https://github.com/spring-cloud/spring-cloud-openfeign Open ...

  6. ARouter源码分析

    源码看过好几遍了,但是总是会忘记,特此记录下 先从注解处理器开始 BaseProcessor是其他三个注解处理器的抽象类,子类去实现process方法.在其中的init方法中会获取我们的module模 ...

  7. devops|中小公司不要做研发效能度量

    我特别反感那些不顾公司现状一上来就想要做研发效能度量的人,尤其是想把研发效能度量当成锤子四处去敲打螺丝钉的人. 没几个人的小公司上来就做研发效能度量,就如同普通人一上来直接问媒婆怎么能娶到迪丽热巴.解 ...

  8. 一文吃透Elasticsearch

    本文已经收录到Github仓库,该仓库包含计算机基础.Java基础.多线程.JVM.数据库.Redis.Spring.Mybatis.SpringMVC.SpringBoot.分布式.微服务.设计模式 ...

  9. MySQL(十一)索引的分类和创建原则

    索引的创建与设计原则 1 索引的声明与使用 1.1 索引的分类 ​ MySQL索引包括普通索引.唯一性索引.全文索引.单列索引.多列索引和空间索引 按照逻辑结构划分,主要有四种:普通索引.唯一性索引. ...

  10. Linux(一)Linux简介、目录结构、网络配置与系统服务

    1 Linux简介 Linux基于Unix,是多用户分时系统 Ctrl + Alt + F2.F3...F6打开多个Linux Shell终端控制器:F1为图形化界面,终端为仿真器 2 Linux文件 ...