【开源项目】Sa-Token快速登录(使用+源码解析)

news2025/1/6 17:55:49

什么是Sa-Token

官网:https://sa-token.dev33.cn

Sa-Token 是一个轻量级 Java 权限认证框架,主要解决:登录认证权限认证Session会话单点登录OAuth2.0微服务网关鉴权 等一系列权限相关问题。
在这里插入图片描述

快速使用

引入Maven依赖

        <!-- web支持 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- Sa-Token-Quick-Login 插件 -->
        <dependency>
            <groupId>cn.dev33</groupId>
            <artifactId>sa-token-quick-login</artifactId>
            <version>1.33.0</version>
        </dependency>

配置参数

server:
  port: 8080

# Sa-Token-Quick-Login 配置
sa:
  # 登录账号
  name: admin
  # 登录密码
  pwd: 123456
  # 是否自动随机生成账号密码 (此项为true时, name与pwd失效)
  auto: false
  # 是否开启全局认证(关闭后将不再强行拦截)
  auth: true
  # 登录页标题
  title: Charles Index 登录
  # 是否显示底部版权信息
  copr: true
  # 指定拦截路径
  include: /**
  # 指定排除路径
  exclude: /test

编写Controller

@RestController
public class TestController {

    /**
     * 不需要认证
     *
     * @return
     */
    @GetMapping("test")
    public String test() {
        return "test";
    }

    /**
     * 需要认证
     *
     * @return
     */
    @GetMapping("test1")
    public String test1() {
        return "test1";
    }
}

测试

  • 访问 http://localhost:8080/test1
    在这里插入图片描述

由于没有登录,被拦截了,到了登录页面

  • 访问 http://localhost:8080/test,可以获取数据。
    在这里插入图片描述

源码解析

  1. 引入sa-token-quick-login,会加载jar包中的spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=cn.dev33.satoken.quick.SaQuickInject
  1. SaQuickInject类上面注解是@Import({SaQuickController.class, SaQuickRegister.class}),所以会添加SaQuickControllerSaQuickRegister
  2. SaQuickController主要是提供登录页面和提供登录接口
@Controller
public class SaQuickController {
    public SaQuickController() {
    }

    @GetMapping({"/saLogin"})
    public String saLogin(HttpServletRequest request) {
        request.setAttribute("cfg", SaQuickManager.getConfig());
        return "sa-login.html";
    }

    @PostMapping({"/doLogin"})
    @ResponseBody
    public SaResult doLogin(String name, String pwd) {
        if (!SaFoxUtil.isEmpty(name) && !SaFoxUtil.isEmpty(pwd)) {
            SaQuickConfig config = SaQuickManager.getConfig();
            if (name.equals(config.getName()) && pwd.equals(config.getPwd())) {
                StpUtil.login(config.getName());
                return SaResult.get(200, "ok", StpUtil.getTokenInfo());
            } else {
                return SaResult.get(500, "账号或密码输入错误", (Object)null);
            }
        } else {
            return SaResult.get(500, "请输入账号和密码", (Object)null);
        }
    }
}
  1. SaQuickRegister是核心,提供了SaServletFilterSaServletFilter用来做拦截认证。
@Configuration
public class SaQuickRegister {
    public SaQuickRegister() {
    }

    @Bean
    @ConfigurationProperties(
        prefix = "sa"
    )
    public SaQuickConfig getSaQuickConfig() {
        return new SaQuickConfig();
    }

    @Bean
    @Order(-101)
    public SaServletFilter getSaServletFilter() {
        return (new SaServletFilter()).addInclude(new String[]{"/**"}).addExclude(new String[]{"/favicon.ico", "/saLogin", "/doLogin", "/sa-res/**"}).setAuth((obj) -> {
            SaRouter.match(SaQuickManager.getConfig().getInclude().split(",")).notMatch(SaQuickManager.getConfig().getExclude().split(",")).check((r) -> {
                if (SaQuickManager.getConfig().getAuth() && !StpUtil.isLogin()) {
                    SaHolder.getRequest().forward("/saLogin");
                    SaRouter.back();
                }

            });
        }).setError((e) -> {
            return e.getMessage();
        });
    }
}
  1. 访问http://localhost:8080/test,看下SaServletFilter是如何放行的。
    // cn.dev33.satoken.filter.SaServletFilter#doFilter
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        try {
            SaRouter.match(this.includeList).notMatch(this.excludeList).check((r) -> {
                this.beforeAuth.run((Object)null);
                this.auth.run((Object)null);
            });
        } catch (StopMatchException var6) {
        } catch (Throwable var7) {
            String result = var7 instanceof BackResultException ? var7.getMessage() : String.valueOf(this.error.run(var7));
            if (response.getContentType() == null) {
                response.setContentType("text/plain; charset=utf-8");
            }

            response.getWriter().print(result);
            return;
        }

        chain.doFilter(request, response);
    }
  1. 该auth方法是在SaQuickRegister类中定义的。因为/test是在配置文件中定义的,所以在执行SaRouter.match(SaQuickManager.getConfig().getInclude().split(",")).notMatch(SaQuickManager.getConfig().getExclude().split(","))后,SaRouterStaff中的isHit变量为false,所以SaRouterStaff#check()不需要执行。
	public SaRouterStaff notMatch(String... patterns) {
        if (this.isHit) {
            this.isHit = !SaRouter.isMatchCurrURI(patterns);
        }

        return this;
    }
  1. test1方法由于不在exclude配置中,所以会执行SaRouterStaff#check()。该方法中主要有两个判断,SaQuickManager.getConfig().getAuth()StpUtil.isLogin() == false。配置中的auth设置为true,所以第一个判断为true。
  2. StpUtil.isLogin()用来判断是否登录。跟踪到获取到token的方法,获取不到token,返回false,跳转到saLogin页面。
getTokenValueNotCut:249, StpLogic (cn.dev33.satoken.stp)
getTokenValue:201, StpLogic (cn.dev33.satoken.stp)
getLoginIdDefaultNull:746, StpLogic (cn.dev33.satoken.stp)
isLogin:659, StpLogic (cn.dev33.satoken.stp)
isLogin:282, StpUtil (cn.dev33.satoken.stp)
  1. 登录方法,SaQuickController#doLogin()。创造token,并且存储在客户端。
login:331, StpLogic (cn.dev33.satoken.stp)
login:293, StpLogic (cn.dev33.satoken.stp)
login:135, StpUtil (cn.dev33.satoken.stp)
doLogin:53, SaQuickController (cn.dev33.satoken.quick.web)
	public void login(Object id, SaLoginModel loginModel) {
		// 1、创建会话 
		String token = createLoginSession(id, loginModel);

		// 2、在当前客户端注入Token 
		setTokenValue(token, loginModel);
	}
  1. 存储在客户端。先保留一份在SaStorage,再存入cookie。
	public void setTokenValue(String tokenValue, SaLoginModel loginModel){
		
		if(SaFoxUtil.isEmpty(tokenValue)) {
			return;
		}
		
		// 1. 将 Token 保存到 [存储器] 里  
		setTokenValueToStorage(tokenValue);
		
		// 2. 将 Token 保存到 [Cookie] 里 
		if (getConfig().getIsReadCookie()) {
			setTokenValueToCookie(tokenValue, loginModel.getCookieTimeout());
		}
		
		// 3. 将 Token 写入到响应头里 
		if(loginModel.getIsWriteHeaderOrGlobalConfig()) {
			setTokenValueToResponseHeader(tokenValue);
		}
	}
  1. 登录的时候,从cookie中获取token,判断是否过期,如果能获取loginId,则判断是登录状态,SaTokenDaoDefaultImpl#get
	@Override
	public String get(String key) {
		clearKeyByTimeout(key);
		return (String)dataMap.get(key);
	}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/144117.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

有奖征集丨大数据/人工智能模型开发征集

大数据人工智能模型开发征集 为助力构建创新型人才培养模式&#xff0c;培养具有创新精神和实践能力的高素质智能技术人才&#xff0c;激发学生积极参与数据科学研究、技术开发、数据学科竞赛等各类社会实践活动的创新热情。依托模型交易平台&#xff0c;为学生提供自主学习…

认识Linux系统结构

Linux 系统一般有 4 个主要部分&#xff1a;内核、shell、文件系统和应用程序。内核、shell 和文件系统一起形成了基本的操作系统结构&#xff0c;它们使得用户可以运行程序、管理文件并使用系统。 Linux内核 内核是操作系统的核心&#xff0c;具有很多最基本功能&#xff0c;…

linux系统中进一步理解设备树

第一&#xff1a;前言 大家好&#xff0c;我是ST。 目录 第一&#xff1a;前言 第二&#xff1a;框图 第三&#xff1a;体验设备树 第四&#xff1a;实验过程分析 第五&#xff1a;实验代码 1、应用程序ledtest.c&#xff1a; 2、驱动层leddrv.c 3、硬件层&#xff1a…

不忘初心,坚持创作和分享,做自己喜欢的事 - 2022 年回顾

不知不觉&#xff0c;来到 Elastic 已经三年多了。在 Elastic 的三年&#xff0c;是疫情发生的三年。对很多人来说&#xff0c;疫情对我们的工作和学习都有很大的变化。好在我还能静下心来&#xff0c;每天坚持学习&#xff0c;不断地创作。记录下来自己的学习及成长经历。我学…

苹果电脑数据回复Aiseesoft Data Recovery

苹果电脑照片误删了怎么找回&#xff0c;数据丢失怎么办&#xff1f;Aiseesoft Data Recovery是专业数据恢复软件&#xff0c;能够帮助你恢复几乎所有删除/丢失的文件&#xff0c;如照片&#xff0c;文件&#xff0c;电子邮件&#xff0c;音频&#xff0c;视频且支持从计算机&a…

C语言深度剖析指针

文章目录 一、指针简单介绍 二、进阶指针的详解 2、1 字符指针 2、2 指针数组 2、3 数组指针 2、3、1 数组指针的定义以用法 2、3、2 数组名和&数组名的区别 2、3、3 数组指针的用法 2、4 函数指针 2、4、1 函数指针的解释 2、4、2 函数指针的举例分析 2、5 函数指针数组 2…

Python 图片转换(Image Conversion) (JPG ⇄ PNG/JPG ⇄ WEBP)

这里我们将使用 PIL&#xff08;Python Imaging Library&#xff09;或 pillow 库&#xff0c;它在 Python 中广泛用于图像处理&#xff0c;Python Imaging Library 中最重要的类是在Image同名模块中定义的类。您可以通过多种方式创建此类的实例&#xff1b;通过从文件加载图像…

高通开发系列 - usb和adb服务启动流程

By: fulinux E-mail: fulinux@sina.com Blog: https://blog.csdn.net/fulinus 喜欢的盆友欢迎点赞和订阅! 你的喜欢就是我写作的动力! 目录 初始化usb相关服务启动adbd服务adbd服务adb devices -l命令串口号丢失问题初始化usb相关服务 /lib/systemd/system/usb.service /etc…

基于yolov5-v7.0开发构建裸土实例分割检测识别模型

yolov5在v7.0的版本中加入了对图像实例分割的全面支持&#xff0c;这里主要就是想基于v7.0的分支来开发构建裸土分割模型&#xff0c;其实在实际计算的时候模型是可以连带着检测任务一起输出结果的&#xff0c;这里我从结果形式上面直观来看应该就是在推理阶段直接基于分割的结…

回顾2022年的历程,展望2023年目标

这里写目录标题回顾2022年博客之星你参加了吗&#xff1f;学习方面写博客方面在涨粉丝方面展望2023回顾2022年 时间如梭&#xff0c;转眼间已经2023年了。 你开始做总结了吗&#xff1f; 博客之星你参加了吗&#xff1f; 这是 2022 博客之星 的竞选帖子&#xff0c; 请你在这…

中国电信分布式物联网操作系统CTWing OS 2.0发布!

近日&#xff0c;2022天翼数字科技生态大会云上隆重开幕&#xff0c;由中国电信天翼物联自主研发的分布式物联网操作系统CTWing OS 2.0最新成果正式发布。CTWing OS 2.0在体系架构、系统功能、系统性能、稳定保障、安全可信、行业赋能六大要素上实现全面提升&#xff0c;全方位…

SQLSERVER 的复合索引和包含索引到底有啥区别?

一&#xff1a;背景 1. 讲故事 在 SQLSERVER 中有非常多的索引&#xff0c;比如&#xff1a;聚集索引&#xff0c;非聚集索引&#xff0c;唯一索引&#xff0c;复合索引&#xff0c;Include索引&#xff0c;交叉索引&#xff0c;连接索引&#xff0c;奇葩索引等等&#xff0c…

首发ML-30s+,一径打响CES激光雷达大战第一枪

作者 | 王博 编辑 | 于婷2023年1月&#xff0c;CES再度在美国拉斯维加斯拉开帷幕。随着车企在车载软硬件上不断加大投入&#xff0c;CES也越发变得像一个高规格的全球车展。 根据研究机构Counterpoint的测算&#xff0c;由于高阶ADAS和Robotaxi普及&#xff0c;到2030年全球激光…

Spring Cloud Netflix 全套组件入门到实战

文章目录简介注册中心核心功能高可用配置服务调用RestTemplateRestTemplateRibbonFegin负载策略超时&重试服务熔断降级机制隔离机制线程池隔离信号量隔离Hystrix仪表板服务路由启用Zuul路由配置参考文档代码仓库通过本文可以给你带来什么&#xff1f;熟悉掌握Spring Cloud&…

关于OPCUA的配套规范

OPC UA中的信息建模能力足够强大&#xff0c;使OPC UA成为定义从简单的数据&#xff08;如工程单位和传感器或设备生成的最大/最小范围&#xff09;到大型复杂关系的理想选择&#xff0c;其中包括涉及数据结构&#xff0c;方法和状态机的复杂对象类型的实例化。也就是说&#x…

mysql数据库的基础操作(一)

一、导入/导出sql脚本 1.1 导入sql脚本 1.1.1 终端导入sql脚本 在mysql中&#xff0c;执行source命令 mysql> source /chenshuai/cs.sql 1.1.2 可视化工具导入sql脚本 在Navicat Premium中&#xff0c;右键这个数据库&#xff0c;然后Execute SQL File 1.2 导出sql脚本…

Redis主从、哨兵、集群模式

众所周知,redis是目前非常流行的缓存中间件之一。在redis官网有这么一段话: redis有着丰富的数据结构&#xff0c;如 字符串&#xff08;strings&#xff09;&#xff0c; 散列&#xff08;hashes&#xff09;&#xff0c; 列表&#xff08;lists&#xff09;&#xff0c; 集合…

Please restart this script from an administrative PowerShell!

执行 npm install --global --vs2019 --production windows-build-tools报一下错误信息 Downloading python-2.7.15.amd64.msi Downloading Python failed. Error: Error: getaddrinfo ENOTFOUND cdn.npmmirror.com at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:…

养老院管理系统|基于JavaWeb开发实现养老院管理系统

作者主页&#xff1a;编程指南针 作者简介&#xff1a;Java领域优质创作者、CSDN博客专家 、掘金特邀作者、多年架构师设计经验、腾讯课堂常驻讲师 主要内容&#xff1a;Java项目、毕业设计、简历模板、学习资料、面试题库、技术互助 收藏点赞不迷路 关注作者有好处 文末获取源…

ROS用pyqt实现GUI界面控制乌龟运动

#!/usr/bin/env python3 #codingutf-8 from PyQt5.QtWidgets import * import sys from window import MainWindow,TurtleWindow import rospy if __name__ __main__: rospy.init_node(turtle_ctrl_node) appQApplication(sys.argv) #窗口展示 windowTurtleWindow() …