广告
返回顶部
首页 > 资讯 > 后端开发 > Python >SpringBoot使用Sa-Token实现登录认证
  • 468
分享到

SpringBoot使用Sa-Token实现登录认证

SpringBoot Sa-Token登录认证SpringBoot 登录认证 2023-05-14 20:05:41 468人浏览 八月长安

Python 官方文档:入门教程 => 点击学习

摘要

目录一、设计思路二、登录与注销三、会话查询四、Token 查询五、来个小测试,加深一下理解一、设计思路 对于一些登录之后才能访问的接口(例如:查询我的账号资料),我们通常的做法是增加

一、设计思路

对于一些登录之后才能访问的接口(例如:查询我的账号资料),我们通常的做法是增加一层接口校验:

  • 如果校验通过,则:正常返回数据。
  • 如果校验未通过,则:抛出异常,告知其需要先进行登录。

那么,判断会话是否登录的依据是什么?我们先来简单分析一下登录访问流程:

  • 用户提交 name + passWord 参数,调用登录接口。
  • 登录成功,返回这个用户的 Token 会话凭证。
  • 用户后续的每次请求,都携带上这个 Token。
  • 服务器根据 Token 判断此会话是否登录成功。

所谓登录认证,指的就是服务器校验账号密码,为用户颁发 Token 会话凭证的过程,这个 Token 也是我们后续判断会话是否登录的关键所在。

动态图演示:

接下来,我们将介绍在 SpringBoot 中如何使用 Sa-Token 完成登录认证操作。

Sa-Token 是一个 java 权限认证框架,主要解决登录认证、权限认证、单点登录、OAuth2、微服务网关鉴权 等一系列权限相关问题。
gitee 开源地址:https://gitee.com/dromara/sa-token

首先在项目中引入 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 即可。

二、登录与注销

根据以上思路,我们需要一个会话登录的函数:

// 会话登录:参数填写要登录的账号id,建议的数据类型:long | int | String, 不可以传入复杂类型,如:User、Admin 等等
StpUtil.login(Object id);     

只此一句代码,便可以使会话登录成功,实际上,Sa-Token 在背后做了大量的工作,包括但不限于:

  • 检查此账号是否之前已有登录
  • 为账号生成 Token 凭证与 Session 会话
  • 通知全局侦听器,xx 账号登录成功
  • 将 Token 注入到请求上下文
  • 等等其它工作……

你暂时不需要完整的了解整个登录过程,你只需要记住关键一点:Sa-Token 为这个账号创建了一个Token凭证,且通过 Cookie 上下文返回给了前端

所以一般情况下,我们的登录接口代码,会大致类似如下:

// 会话登录接口 
@RequestMapping("doLogin")
public SaResult doLogin(String name, String pwd) {
    // 第一步:比对前端提交的账号名称、密码
    if("zhang".equals(name) && "123456".equals(pwd)) {
        // 第二步:根据账号id,进行登录 
        StpUtil.login(10001);
        return SaResult.ok("登录成功");
    }
    return SaResult.error("登录失败");
}

如果你对以上代码阅读没有压力,你可能会注意到略显奇怪的一点:此处仅仅做了会话登录,但并没有主动向前端返回 Token 信息。
是因为不需要吗?严格来讲是需要的,只不过 StpUtil.login(id) 方法利用了 Cookie 自动注入的特性,省略了你手写返回 Token 的代码。

如果你对 Cookie 功能还不太了解,也不用担心,我们会在之后的 [ 前后端分离 ] 章节中详细的阐述 Cookie 功能,现在你只需要了解最基本的两点:

  • Cookie 可以从后端控制往浏览器中写入 Token 值。
  • Cookie 会在前端每次发起请求时自动提交 Token 值。

因此,在 Cookie 功能的加持下,我们可以仅靠 StpUtil.login(id) 一句代码就完成登录认证。

除了登录方法,我们还需要:

// 当前会话注销登录
StpUtil.loGout();

// 获取当前会话是否已经登录,返回true=已登录,false=未登录
StpUtil.isLogin();

// 检验当前会话是否已经登录, 如果未登录,则抛出异常:`NotLoginException`
StpUtil.checkLogin();

异常 NotLoginException 代表当前会话暂未登录,可能的原因有很多:
前端没有提交 Token、前端提交的 Token 是无效的、前端提交的 Token 已经过期 …… 等等。

Sa-Token 未登录场景值参照表:

场景值对应常量含义说明
-1NotLoginException.NOT_TOKEN未能从请求中读取到 Token
-2NotLoginException.INVALID_TOKEN已读取到 Token,但是 Token无效
-3NotLoginException.TOKEN_TIMEOUT已读取到 Token,但是 Token已经过期
-4NotLoginException.BE_REPLACED已读取到 Token,但是 Token 已被顶下线
-5NotLoginException.KICK_OUT已读取到 Token,但是 Token 已被踢下线

那么,如何获取场景值呢?废话少说直接上代码:

// 全局异常拦截(拦截项目中的NotLoginException异常)
@ExceptionHandler(NotLoginException.class)
public SaResult handlerNotLoginException(NotLoginException nle)
        throws Exception {

    // 打印堆栈,以供调试
    nle.printStackTrace(); 
    
    // 判断场景值,定制化异常信息 
    String message = "";
    if(nle.getType().equals(NotLoginException.NOT_TOKEN)) {
        message = "未提供token";
    }
    else if(nle.getType().equals(NotLoginException.INVALID_TOKEN)) {
        message = "token无效";
    }
    else if(nle.getType().equals(NotLoginException.TOKEN_TIMEOUT)) {
        message = "token已过期";
    }
    else if(nle.getType().equals(NotLoginException.BE_REPLACED)) {
        message = "token已被顶下线";
    }
    else if(nle.getType().equals(NotLoginException.KICK_OUT)) {
        message = "token已被踢下线";
    }
    else {
        message = "当前会话未登录";
    }
    
    // 返回给前端
    return SaResult.error(message);
}

注意:以上代码并非处理逻辑的最佳方式,只为以最简单的代码演示出场景值的获取与应用,大家可以根据自己的项目需求来定制化处理

三、会话查询

// 获取当前会话账号id, 如果未登录,则抛出异常:`NotLoginException`
StpUtil.getLoginId();

// 类似查询api还有:
StpUtil.getLoginIdAsString();    // 获取当前会话账号id, 并转化为`String`类型
StpUtil.getLoginIdAsInt();       // 获取当前会话账号id, 并转化为`int`类型
StpUtil.getLoginIdAsLong();      // 获取当前会话账号id, 并转化为`long`类型

// ---------- 指定未登录情形下返回的默认值 ----------

// 获取当前会话账号id, 如果未登录,则返回null 
StpUtil.getLoginIdDefaultNull();

// 获取当前会话账号id, 如果未登录,则返回默认值 (`defaultValue`可以为任意类型)
StpUtil.getLoginId(T defaultValue);

四、Token 查询

// 获取当前会话的token值
StpUtil.getTokenValue();

// 获取当前`StpLogic`的token名称
StpUtil.getTokenName();

// 获取指定token对应的账号id,如果未登录,则返回 null
StpUtil.getLoginIdByToken(String tokenValue);

// 获取当前会话剩余有效期(单位:s,返回-1代表永久有效)
StpUtil.getTokenTimeout();

// 获取当前会话的token信息参数
StpUtil.getTokenInfo();

TokenInfo 是 Token 信息 Model,用来描述一个 Token 的常用参数:

{
    "tokenName": "satoken",           // token名称
    "tokenValue": "e67b99f1-3D7a-4a8d-bb2f-e888a0805633",      // token值
    "isLogin": true,                  // 此token是否已经登录
    "loginId": "10001",               // 此token对应的LoginId,未登录时为null
    "loginType": "login",              // 账号类型标识
    "tokenTimeout": 2591977,          // token剩余有效期 (单位: 秒)
    "sessionTimeout": 2591977,        // User-Session剩余有效时间 (单位: 秒)
    "tokenSessionTimeout": -2,        // Token-Session剩余有效时间 (单位: 秒) (-2表示系统中不存在这个缓存)
    "tokenActivityTimeout": -1,       // token剩余无操作有效时间 (单位: 秒)
    "loginDevice": "default-device"   // 登录设备类型 
}

五、来个小测试,加深一下理解

新建 LoginAuthController,复制以下代码

package com.pj.cases.use;

import org.springframework.WEB.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;


@RestController
@RequestMapping("/acc/")
public class LoginAuthController {

    // 会话登录接口  ---- Http://localhost:8081/acc/doLogin?name=zhang&pwd=123456
    @RequestMapping("doLogin")
    public SaResult doLogin(String name, String pwd) {
        
        // 第一步:比对前端提交的 账号名称 & 密码 是否正确,比对成功后开始登录 
        //         此处仅作模拟示例,真实项目需要从数据库中查询数据进行比对 
        if("zhang".equals(name) && "123456".equals(pwd)) {
            
            // 第二步:根据账号id,进行登录 
            //         此处填入的参数应该保持用户表唯一,比如用户id,不可以直接填入整个 User 对象 
            StpUtil.login(10001);
            
            // SaResult 是 Sa-Token 中对返回结果的简单封装,下面的示例将不再赘述 
            return SaResult.ok("登录成功");
        }
        
        return SaResult.error("登录失败");
    }

    // 查询当前登录状态  ---- http://localhost:8081/acc/isLogin
    @RequestMapping("isLogin")
    public SaResult isLogin() {
        // StpUtil.isLogin() 查询当前客户端是否登录,返回 true 或 false 
        boolean isLogin = StpUtil.isLogin();
        return SaResult.ok("当前客户端是否登录:" + isLogin);
    }

    // 校验当前登录状态  ---- http://localhost:8081/acc/checkLogin
    @RequestMapping("checkLogin")
    public SaResult checkLogin() {
        // 检验当前会话是否已经登录, 如果未登录,则抛出异常:`NotLoginException`
        StpUtil.checkLogin();

        // 抛出异常后,代码将走入全局异常处理(GlobalException.java),如果没有抛出异常,则代表通过了登录校验,返回下面信息 
        return SaResult.ok("校验登录成功,这行字符串是只有登录后才会返回的信息");
    }

    // 获取当前登录的账号是谁  ---- http://localhost:8081/acc/getLoginId
    @RequestMapping("getLoginId")
    public SaResult getLoginId() {
        // 需要注意的是,StpUtil.getLoginId() 自带登录校验效果
        // 也就是说如果在未登录的情况下调用这句代码,框架就会抛出 `NotLoginException` 异常,效果和 StpUtil.checkLogin() 是一样的 
        Object userId = StpUtil.getLoginId();
        System.out.println("当前登录的账号id是:" + userId);
        
        // 如果不希望 StpUtil.getLoginId() 触发登录校验效果,可以填入一个默认值
        // 如果会话未登录,则返回这个默认值,如果会话已登录,将正常返回登录的账号id 
        Object userId2 = StpUtil.getLoginId(0);
        System.out.println("当前登录的账号id是:" + userId2);
        
        // 或者使其在未登录的时候返回 null 
        Object userId3 = StpUtil.getLoginIdDefaultNull();
        System.out.println("当前登录的账号id是:" + userId3);
        
        // 类型转换:
        // StpUtil.getLoginId() 返回的是 Object 类型,你可以使用以下方法指定其返回的类型 
        int userId4 = StpUtil.getLoginIdAsInt();  // 将返回值转换为 int 类型 
        long userId5 = StpUtil.getLoginIdAsLong();  // 将返回值转换为 long 类型 
        String userId6 = StpUtil.getLoginIdAsString();  // 将返回值转换为 String 类型 
        
        // 疑问:数据基本类型不是有八个吗,为什么只封装以上三种类型的转换?
        // 因为大多数项目都是拿 int、long 或 String 声明 UserId 的类型的,实在没见过哪个项目用 double、float、boolean 之类来声明 UserId 
        System.out.println("当前登录的账号id是:" + userId4 + " --- " + userId5 + " --- " + userId6);
        
        // 返回给前端 
        return SaResult.ok("当前客户端登录的账号id是:" + userId);
    }

    // 查询 Token 信息  ---- http://localhost:8081/acc/tokenInfo
    @RequestMapping("tokenInfo")
    public SaResult tokenInfo() {
        // TokenName 是 Token 名称的意思,此值也决定了前端提交 Token 时应该使用的参数名称 
        String tokenName = StpUtil.getTokenName();
        System.out.println("前端提交 Token 时应该使用的参数名称:" + tokenName);
        
        // 使用 StpUtil.getTokenValue() 获取前端提交的 Token 值 
        // 框架默认前端可以从以下三个途径中提交 Token:
        //         Cookie         (浏览器自动提交)
        //         Header头    (代码手动提交)
        //         Query 参数    (代码手动提交) 例如: /user/getInfo?satoken=xxxx-xxxx-xxxx-xxxx 
        // 读取顺序为: Query 参数 --> Header头 -- > Cookie 
        // 以上三个地方都读取不到 Token 信息的话,则视为前端没有提交 Token 
        String tokenValue = StpUtil.getTokenValue();
        System.out.println("前端提交的Token值为:" + tokenValue);
        
        // TokenInfo 包含了此 Token 的大多数信息 
        SaTokenInfo info = StpUtil.getTokenInfo();
        System.out.println("Token 名称:" + info.getTokenName());
        System.out.println("Token 值:" + info.getTokenValue());
        System.out.println("当前是否登录:" + info.getIsLogin());
        System.out.println("当前登录的账号id:" + info.getLoginId());
        System.out.println("当前登录账号的类型:" + info.getLoginType());
        System.out.println("当前登录客户端的设备类型:" + info.getLoginDevice());
        System.out.println("当前 Token 的剩余有效期:" + info.getTokenTimeout()); // 单位:秒,-1代表永久有效,-2代表值不存在
        System.out.println("当前 Token 的剩余临时有效期:" + info.getTokenActivityTimeout()); // 单位:秒,-1代表永久有效,-2代表值不存在
        System.out.println("当前 User-Session 的剩余有效期" + info.getSessionTimeout()); // 单位:秒,-1代表永久有效,-2代表值不存在
        System.out.println("当前 Token-Session 的剩余有效期" + info.getTokenSessionTimeout()); // 单位:秒,-1代表永久有效,-2代表值不存在
        
        // 返回给前端 
        return SaResult.data(StpUtil.getTokenInfo());
    }
    
    // 会话注销  ---- http://localhost:8081/acc/logout
    @RequestMapping("logout")
    public SaResult logout() {
        // 退出登录会清除三个地方的数据:
        //         1、Redis中保存的 Token 信息
        //         2、当前请求上下文中保存的 Token 信息 
        //         3、Cookie 中保存的 Token 信息(如果未使用Cookie模式则不会清除)
        StpUtil.logout();
        
        // StpUtil.logout() 在未登录时也是可以调用成功的,
        // 也就是说,无论客户端有没有登录,执行完 StpUtil.logout() 后,都会处于未登录状态 
        System.out.println("当前是否处于登录状态:" + StpUtil.isLogin());
        
        // 返回给前端 
        return SaResult.ok("退出登录成功");
    }
    
}

代码注释已针对每一步操作做出详细解释,大家可根据可参照注释中的访问链接进行逐步测试。

本示例代码已上传至 Gitee,可参考:

Sa-Token 登录认证示例

参考资料
Gitee 仓库地址:https://gitee.com/dromara/sa-token
GitHub 仓库地址:https://github.com/dromara/sa-token
Sa-Token 在线文档:https://sa-token.dev33.cn/

到此这篇关于SpringBoot使用Sa-Token实现登录认证的文章就介绍到这了,更多相关SpringBoot Sa-Token登录认证内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: SpringBoot使用Sa-Token实现登录认证

本文链接: https://www.lsjlt.com/news/204533.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • SpringBoot使用Sa-Token实现登录认证
    目录一、设计思路二、登录与注销三、会话查询四、Token 查询五、来个小测试,加深一下理解一、设计思路 对于一些登录之后才能访问的接口(例如:查询我的账号资料),我们通常的做法是增加...
    99+
    2023-05-14
    SpringBoot Sa-Token登录认证 SpringBoot 登录认证
  • SpringBoot怎么使用Sa-Token实现登录认证
    这篇文章主要讲解了“SpringBoot怎么使用Sa-Token实现登录认证”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“SpringBoot怎么使用Sa-Token实现登录认证”吧!一、设...
    99+
    2023-07-05
  • SpringBoot使用Sa-Token实现权限认证
    目录一、设计思路二、获取当前账号权限码集合三、权限校验四、角色校验五、拦截全局异常六、权限通配符七、如何把权限精确到按钮级?八、前端有了鉴权后端还需要鉴权吗?九、来个小示例,加深一下...
    99+
    2023-05-17
    SpringBoot Sa-Token权限认证 SpringBoot 权限认证
  • SpringBoot整合Sa-Token实现登录认证的示例代码
    目录依赖登录退出登录前后端分离今天分享的是 Spring Boot 整合 Sa-Token 实现登录认证。 依赖 首先,我们需要添加依赖: 关...
    99+
    2022-11-13
  • SpringBoot如何使用Sa-Token实现权限认证
    今天小编给大家分享一下SpringBoot如何使用Sa-Token实现权限认证的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。...
    99+
    2023-07-06
  • PHP实现JWT的Token登录认证
    1、JWT简介 JSON Web Token(缩写 JWT),是目前最流行的跨域认证解决方案。 session登录认证方案:用户从客户端传递用户名、密码等信息,服务端认证后将信息存储在session中,将session_id放到cookie...
    99+
    2017-03-29
    PHP实现Token登录认证 PHP Token认证 Token登录认证
  • SpringBoot整合token实现登录认证的示例代码
    1.pom.xml <dependencies> <dependency> <groupId>org.springframework.b...
    99+
    2022-11-13
  • SpringBoot集成JWT实现Token登录验证
    目录 1.1 JWT是什么? 1.2 JWT主要使用场景 1.3 JWT请求流程 1.4 JWT结构 二,SpringBoot集成JWT具体实现过程 2.1添加相关依赖 2.2自定义跳出拦截器的注解 2.3自定义全局统一返回值方法,异常类...
    99+
    2023-09-06
    spring boot 后端 java
  • PHP如何实现JWT的Token登录认证
    本篇内容介绍了“PHP如何实现JWT的Token登录认证”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1、JWT简介JSON Web Tok...
    99+
    2023-06-21
  • SpringBoot登录验证token拦截器的实现
    目录注解定义token生成与验证拦截器定义拦截器配置定义拦截器的方法执行类注解使用返回值-全局异常类定义各种测试不传token制造可行的假token伪造token测试拓展:从请求中获...
    99+
    2022-11-13
  • SpringBoot登录验证token拦截器如何实现
    这篇文章主要讲解了“SpringBoot登录验证token拦截器如何实现”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“SpringBoot登录验证token拦截器如何实现”吧!用户访问接口验...
    99+
    2023-07-02
  • SpringBoot如何实现token登录
    这篇文章主要为大家展示了“SpringBoot如何实现token登录”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“SpringBoot如何实现token登录”这篇文章吧。为什么引入token机制...
    99+
    2023-06-29
  • VUE实现token登录验证
    本文实例为大家分享了VUE实现token登录验证的具体代码,供大家参考,具体内容如下 实现这个登录功能的过程真是一波三折,中途出现了bug,整了两三天才解决了问题,心力交瘁,简直一个...
    99+
    2022-11-12
  • Java轻量级权限认证框架Sa-Token的使用
    目录前言Sa-Token 是什么如何使用?引入依赖示例代码常用方法常用注解注册拦截器Spring boot 集成1、在application.yml配置2、通过代码配置总结前言 相信...
    99+
    2022-11-13
  • SpringSecurity实现前后端分离登录token认证详解
    目录 1. SpringSecurity概述 1.1 权限框架 1.1.1 Apache Shiro 1.1.2 SpringSecurity 1.1.3 权限框架的选择 1.2 授权和认证 1.3 SpringSecurity的功能 ...
    99+
    2023-08-31
    spring java spring boot
  • SpringBoot security安全认证登录如何实现
    本文小编为大家详细介绍“SpringBoot security安全认证登录如何实现”,内容详细,步骤清晰,细节处理妥当,希望这篇“SpringBoot security安全认证登录如何实现”文章能帮助大家解决疑惑,下面跟...
    99+
    2023-07-05
  • Vue实现用户登录及token验证
    在前后端完全分离的情况下,Vue项目中实现token验证大致思路如下: 1、第一次登录的时候,前端调后端的登陆接口,发送用户名和密码 2、后端收到请求,验证用户名和密码,验证成功,就...
    99+
    2022-11-12
  • Java如何实现Token登录验证
    这篇文章主要介绍“Java如何实现Token登录验证”,在日常操作中,相信很多人在Java如何实现Token登录验证问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java如何实现Token登录验证”的疑惑有所...
    99+
    2023-07-05
  • django restframework使用redis实现token认证
    目录一、前言二、详解1. 前期准备2. 配置redis3. 将token写入redis3.1 原来的登录代码3.2 重写后的登录代码3.3 登录后redis存储的用户记录4. 重写认...
    99+
    2022-11-12
  • SpringBoot JWT实现token登录刷新功能
    目录1. 什么是JWT2. JWT组成部分3. JWT加密方式4.实战5.总结1. 什么是JWT Json web token (JWT) 是为了在网络应用环境间传递声明而执行的一种...
    99+
    2022-11-12
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作