微服务网关SpringCloudGateway+SaToken鉴权

news2025/6/7 21:30:04

目录

概念

前置知识回顾

拿到UserInfo 用于自定义权限和角色的获取逻辑

最后进行要进行 satoken 过滤器全局配置


概念

做权限认证的时候 我们首先要明确两点

我们需要的角色有几种 我们需要的权限有几种

角色 分两种

ADMIN 管理员 :可管理商品

CUSTIOMER 普通用户 :

权限 分四种

BASIC 基本权限 :可浏览商品

AUTU 已实名认证权限 :可下单支付

FROZEN 被冻结用户权限

NONE 没有任何权限

前置知识回顾

在阅读完 sa-token 的文档后

我发现原来权限验证如此简单

我们只需要 使用StpUtil即可

这个在开发博客的时候写过相关的

// 用户已存在,直接登录
StpUtil.login(userInfo.getUserId(), new SaLoginModel().setIsLastingCookie(loginParam.getRememberMe())
       .setTimeout(DEFAULT_LOGIN_SESSION_TIMEOUT));
// 将用户信息存入会话
StpUtil.getSession().set(userInfo.getUserId().toString(), userInfo);
// 创建登录结果对象
LoginVO loginVO = new LoginVO(userInfo);
// 返回登录成功响应
return Result.success(loginVO);

拿到UserInfo 用于自定义权限和角色的获取逻辑

我们在用 StpUtil 去拿这个登录信息

进行校验

很容易理解 我们在登录模块 放入了一个 UserInfo 对象进去

包含了用户了信息

package cn.hollis.nft.turbo.api.user.response.data;

import cn.hollis.nft.turbo.api.user.constant.UserRole;
import cn.hollis.nft.turbo.api.user.constant.UserStateEnum;
import com.github.houbb.sensitive.annotation.strategy.SensitiveStrategyPhone;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import java.util.Date;

/**
 * @author Hollis
 */
@Getter
@Setter
@NoArgsConstructor
public class UserInfo extends BasicUserInfo {

    private static final long serialVersionUID = 1L;

    /**
     * 手机号
     */
    @SensitiveStrategyPhone
    private String telephone;

    /**
     * 状态
     *
     * @see UserStateEnum
     */
    private String state;

    /**
     * 区块链地址
     */
    private String blockChainUrl;

    /**
     * 区块链平台
     */
    private String blockChainPlatform;

    /**
     * 实名认证
     */
    private Boolean certification;

    /**
     * 用户角色
     */
    private UserRole userRole;

    /**
     * 邀请码
     */
    private String inviteCode;

    /**
     * 注册时间
     */
    private Date createTime;

    public boolean userCanBuy() {

        if (this.getUserRole() != null && !this.getUserRole().equals(UserRole.CUSTOMER)) {
            return false;
        }
        // 判断买家状态
        if (this.getState() != null && !this.getState().equals(UserStateEnum.ACTIVE.name())) {
            return false;
        }
        // 判断买家状态
        if (this.getState() != null && !this.getCertification()) {
            return false;
        }
        return true;
    }
}

我们sa-token 提供的接口中重写权限校验方法

实现stpInterface 调用处理这个接口方法

我们就是再把这个对象拿出来

// 根据用户登录ID和登录类型返回不同的权限列表
UserInfo userInfo = (UserInfo) StpUtil.getSessionByLoginId(loginId).get((String) loginId);

然后找到权限 返回枚举值

枚举值要包装成 list 类型

这边返回的是List类型

这些文档里都有...

package cn.hollis.nft.turbo.gateway.auth;

import cn.dev33.satoken.stp.StpInterface;
import cn.dev33.satoken.stp.StpUtil;
import cn.hollis.nft.turbo.api.user.constant.UserPermission;
import cn.hollis.nft.turbo.api.user.constant.UserRole;
import cn.hollis.nft.turbo.api.user.constant.UserStateEnum;
import cn.hollis.nft.turbo.api.user.response.data.UserInfo;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * 自定义权限验证接口实现类
 * StpInterface 接口用于自定义权限和角色的获取逻辑。
 * StpInterfaceImpl 类实现了 StpInterface 接口,通过用户的会话信息动态获取用户的权限和角色列表。
 * 在 Sa - Token 框架进行权限验证时,会调用该类的方法来确定用户是否具备相应的权限和角色。
 * 注意:这边通过用户会话信息动态获取用户权限和角色列表
 *
 * @author Hollis
 */
@Component
public class StpInterfaceImpl implements StpInterface {

    /**
     * 根据用户的登录 ID 和登录类型获取用户的权限列表
     *
     * @param loginId  用户的登录 ID
     * @param loginType 用户的登录类型
     * @return 用户的权限列表,以字符串集合形式返回
     */
    @Override
    public List<String> getPermissionList(Object loginId, String loginType) {
        // 从会话中根据登录 ID 获取用户信息
        UserInfo userInfo = (UserInfo) StpUtil.getSessionByLoginId(loginId).get((String) loginId);

        // 如果用户角色是管理员,或者用户状态为激活状态、已认证状态
        if (userInfo.getUserRole() == UserRole.ADMIN
                || userInfo.getState().equals(UserStateEnum.ACTIVE.name())
                || userInfo.getState().equals(UserStateEnum.AUTH.name()) ) {
            // 赋予用户基础权限和认证权限
            return List.of(UserPermission.BASIC.name(), UserPermission.AUTH.name());
        }

        // 如果用户状态为初始状态
        if (userInfo.getState().equals(UserStateEnum.INIT.name())) {
            // 赋予用户基础权限
            return List.of(UserPermission.BASIC.name());
        }

        // 如果用户状态为冻结状态
        if (userInfo.getState().equals(UserStateEnum.FROZEN.name())) {
            // 赋予用户冻结权限
            return List.of(UserPermission.FROZEN.name());
        }

        // 其他情况,赋予用户无权限
        return List.of(UserPermission.NONE.name());
    }

    /**
     * 根据用户的登录 ID 和登录类型获取用户的角色列表
     *
     * @param loginId  用户的登录 ID
     * @param loginType 用户的登录类型
     * @return 用户的角色列表,以字符串集合形式返回
     */
    @Override
    public List<String> getRoleList(Object loginId, String loginType) {
        // 从会话中根据登录 ID 获取用户信息
        UserInfo userInfo = (UserInfo) StpUtil.getSessionByLoginId(loginId).get((String) loginId);
        // 如果用户角色是管理员
        if (userInfo.getUserRole() == UserRole.ADMIN) {
            // 返回管理员角色
            return List.of(UserRole.ADMIN.name());
        }
        // 其他情况,返回普通用户角色
        return List.of(UserRole.CUSTOMER.name());
    }
}

最后进行要进行 satoken 过滤器全局配置

SaReactorFilter

package cn.hollis.nft.turbo.gateway.auth;

import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.exception.NotPermissionException;
import cn.dev33.satoken.exception.NotRoleException;
import cn.dev33.satoken.reactor.filter.SaReactorFilter;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
import cn.hollis.nft.turbo.api.user.constant.UserPermission;
import cn.hollis.nft.turbo.api.user.constant.UserRole;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * sa-token的全局配置类,用于配置鉴权过滤器和异常处理逻辑
 *
 * @author Hollis
 */
@Configuration
@Slf4j
public class SaTokenConfigure {

    /**
     * 创建并配置 SaReactorFilter 实例,该过滤器用于对请求进行鉴权和异常处理
     *
     * @return 配置好的 SaReactorFilter 实例
     */
    @Bean
    public SaReactorFilter getSaReactorFilter() {
        return new SaReactorFilter()
                // 配置需要拦截的请求地址,/** 表示拦截所有请求
                .addInclude("/**")
                // 配置不需要拦截的请求地址,这里排除了网站图标请求
                .addExclude("/favicon.ico")
                // 设置鉴权方法,每次请求进入时会执行该方法进行鉴权
                .setAuth(obj -> {
                    // 登录校验:拦截所有路由,但排除指定的开放路由,对其他请求进行登录状态检查
                    SaRouter.match("/**").notMatch("/auth/**", "/collection/collectionList", "/collection/collectionInfo", "/wxPay/**").check(r -> StpUtil.checkLogin());
                    // 权限认证:针对不同模块的请求,校验不同的权限
                    // 管理界面请求需要用户具备管理员角色
                    SaRouter.match("/admin/**", r -> StpUtil.checkRole(UserRole.ADMIN.name()));
                    // 下单界面请求需要用户具备实名认证权限
                    SaRouter.match("/trade/**", r -> StpUtil.checkPermission(UserPermission.AUTH.name()));
                    // 用户界面请求需要用户具备基本权限或冻结权限
                    SaRouter.match("/user/**", r -> StpUtil.checkPermissionOr(UserPermission.BASIC.name(), UserPermission.FROZEN.name()));
                    // 商品界面请求需要用户具备基本权限或冻结权限
                    SaRouter.match("/order/**", r -> StpUtil.checkPermissionOr(UserPermission.BASIC.name(),UserPermission.FROZEN.name()));
                })
                // 设置异常处理方法,当鉴权方法抛出异常时会进入该方法进行处理
                .setError(this::getSaResult);
    }

    /**
     * 根据不同的异常类型,返回相应的错误信息
     *
     * @param throwable 捕获到的异常对象
     * @return 封装了错误信息的 SaResult 对象
     */
    private SaResult getSaResult(Throwable throwable) {
        switch (throwable) {
            // 处理用户未登录异常
            case NotLoginException notLoginException:
                // 记录错误日志
                log.error("请先登录");
                // 返回未登录的错误信息
                return SaResult.error("请先登录");
            // 处理用户角色不匹配异常
            case NotRoleException notRoleException:
                // 判断是否是管理员角色权限问题
                if (UserRole.ADMIN.name().equals(notRoleException.getRole())) {
                    // 记录越权使用的错误日志
                    log.error("请勿越权使用!");
                    // 返回越权使用的错误信息
                    return SaResult.error("请勿越权使用!");
                }
                // 记录无权限操作的错误日志
                log.error("您无权限进行此操作!");
                // 返回无权限操作的错误信息
                return SaResult.error("您无权限进行此操作!");
            // 处理用户权限不足异常
            case NotPermissionException notPermissionException:
                // 判断是否是实名认证权限问题
                if (UserPermission.AUTH.name().equals(notPermissionException.getPermission())) {
                    // 记录需要实名认证的错误日志
                    log.error("请先完成实名认证!");
                    // 返回需要实名认证的错误信息
                    return SaResult.error("请先完成实名认证!");
                }
                // 记录无权限操作的错误日志
                log.error("您无权限进行此操作!");
                // 返回无权限操作的错误信息
                return SaResult.error("您无权限进行此操作!");
            // 处理其他未知异常
            default:
                // 返回异常的错误信息
                return SaResult.error(throwable.getMessage());
        }
    }
}

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

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

相关文章

永磁同步电机控制算法--模糊PI转速控制器

一、原理介绍 在常规的PID控制系统的基础上提出了一种模糊PID以及矢量变换方法相结合的控制系统&#xff0c;经过仿真分析对比证明&#xff1a; 模糊PID控制系统能够有效的提高永磁同步电机的转速响应速度&#xff0c;降低转矩脉动&#xff0c;增强了整体控制系统的抗干扰能力…

Elasticsearch集群最大分片数设置详解:从问题到解决方案

目录 前言 1 问题背景&#xff1a;重启后设置失效 2 核心概念解析 2.1 什么是分片(Shard)&#xff1f; 2.2 cluster.max_shards_per_node的作用 2.3 默认值是多少&#xff1f; 3 参数设置的两种方式 3.2 持久性设置(persistent) 3.2 临时设置(transient) 4 问题解决方…

DVWA全靶场

目录 暴破 Low - 万能密码 Medium - 转义 High - Token Impossible 命令注入 CSRF跨站请求伪造 - 抓包 Low Medium - 域名限制 High - 域名限制xss 文件包含 - 页面点点点 Low Medium - 过滤http:// High - file Impossible - 写死 文件上传 Low Medium - 文件…

【反无人机检测】C2FDrone:基于视觉Transformer网络的无人机间由粗到细检测

C2FDrone&#xff1a;基于视觉Transformer网络的无人机间由粗到细检测 C2FDrone: Coarse-to-Fine Drone-to-Drone Detection using Vision Transformer Networks 论文链接 摘要 摘要——基于视觉的无人机间检测系统在碰撞规避、反制敌对无人机和搜救行动等应用中至关重要。然…

Android 本地存储路径说明

一、背景 作为一个开发者,我们经常需要通过缓存一些文件到SD卡中,常见的方式就是,通过: File sdCard Environment.getExternalStorageDirectory(); 获取SD卡根目录,然后自定义文件/文件名进行文件存储.这样做法的结果就是,当手机安装了大量的app时&#xff0c;SD卡根目录会…

国产pcie switch 8748+飞腾/龙芯/昇腾高速存储方案设计

方案概述 本设计以国微PCIe Switch 8748为核心交换芯片&#xff0c;通过多端口PCIe 4.0/5.0通道连接飞腾ARM架构处理器、龙芯LoongArch处理器及昇腾AI加速卡&#xff0c;构建支持NVMe协议的高速存储集群&#xff0c;目标实现6.5GB/s以上的可持续带宽。 硬件架构 处理器选型 飞…

如何使用插件和子主题添加WordPress自定义CSS(附:常见错误)

您是否曾经想更改网站外观的某些方面&#xff0c;但不知道怎么做&#xff1f;有一个解决方案——您可以将自定义 CSS&#xff08;层叠样式表&#xff09;添加到您的WordPress网站&#xff01; 在本文中&#xff0c;我们将讨论您需要了解的有关CSS的所有知识以及如何使用它来修…

开始在本地部署自己的 Gitea 服务器

0.简介 在软件开发和团队协作中&#xff0c;代码管理是至关重要的环节。笔者一直使用gitblit管理自己的仓库。然鹅&#xff0c;这个软件已经很久没有更新了。经过多方考察&#xff0c;发现Gitea 是一款轻量级的开源代码托管平台&#xff0c;具有易于部署、资源占用少、功能丰富…

7.2.1_顺序查找

知识总览&#xff1a; 顺序查找&#xff1a; 算法思想&#xff1a; 从头到脚挨个找或者从脚到头挨个找适用于线性表(顺序存储和链式存储都适用)&#xff0c;又叫线性查找 实现&#xff1a; 1个数组elem指向数组的起始位置&#xff0c;索引从0开始遍历数组直到找到目标值返回…

智能制造数字孪生全要素交付一张网:智造中枢,孪生领航,共建智造生态共同体

在制造业转型升级的浪潮中&#xff0c;数字孪生技术正成为推动行业变革的核心引擎。从特斯拉通过数字孪生体实现车辆全生命周期优化&#xff0c;到海尔卡奥斯工业互联网平台赋能千行百业&#xff0c;数字孪生技术已从概念验证走向规模化落地。通过构建覆盖全国的交付网络&#…

stylus - 新生代CSS预处理框架

stylus是什么 Stylus 是一种 CSS 预处理器&#xff0c;它扩展了 CSS 的功能&#xff0c;使得编写样式变得更简洁和高效。Stylus 允许使用嵌套、变量、混入等编程功能&#xff0c;这些功能可以极大地提高开发效率和代码的可维护性。 stylus中文文档 https://stylus.uihtm.co…

BugKu Web渗透之网站被hei(仅仅是ctf题目名称)

启动场景&#xff0c;打开网页&#xff0c;显示如下&#xff1a; 目前没有看出任何异常。 步骤一&#xff1a; 右键查看源代码。源代码较多&#xff0c;也没发现异常。 步骤二&#xff1a; 用dirsearch扫描网站目录。 如图&#xff1a; 看起来shell.php很可疑。 步骤三&…

关于华为仓颉编程语言

文章目录 一、基本概况二、技术特点1. 多范式编程2. 原生智能化3. 高性能与安全4. 全场景兼容 三、编译器与开发工具四、语言相似性对比五、行业应用实例总结 最近经常看到这个东西&#xff0c;于是搜了一下&#xff0c;整理了一些内容&#xff0c;水一篇&#xff0c;以后慢慢研…

解决el-select选择框右侧下拉箭头遮挡文字问题

如图所示&#xff1a; el-select长度较短的时候&#xff0c;选择框右侧下拉箭头会遮挡选中的数据 选中数据被遮挡 解决办法&#xff1a; 组件如下&#xff1a; <td class"fmtd" :colspan"col.ptproCupNum" v-for"col in row" :key"…

20250603在荣品的PRO-RK3566开发板的Android13下的使用命令行来查看RK3566的温度【显示优化版本】

20250603在荣品的PRO-RK3566开发板的Android13下的使用命令行来查看RK3566的温度【显示优化版本】 2025/6/3 11:58 RK3566的cpu运行效率 top busybox top rk3566_t:/ # rk3566_t:/ # rk3566_t:/ # cd /sys/class/thermal/ rk3566_t:/sys/class/thermal # ls -l rk3566_t:/sys/c…

C语言字符数组初始化的5种方法(附带实例)

所谓初始化&#xff0c;就是在定义的同时进行赋值。 C语言中&#xff0c;初始化字符数组的方式多样&#xff0c;每种方式都有其特定的用途和优势。 1、使用字符串字面量初始化 最常见和简洁的初始化方式是使用字符串字面量。在这种方法中&#xff0c;我们直接将一个用双引号…

npm run dev 报错:Error: error:0308010C:digital envelope routines::unsupported

npm run dev时报错如下 原因&#xff1a;更换node版本导致 解决&#xff1a; 修改package.json文件&#xff0c;在相关构建命令之前加入 SET NODE_OPTIONS–openssl-legacy-provider 运行成功

基于LLaMA-Factory和Easy Dataset的Qwen3微调实战:从数据准备到LoRA微调推理评估的全流程指南

随着开源大模型如 LLaMA、Qwen 和 Baichuan 的广泛应用&#xff0c;其基于通用数据的训练方式在特定下游任务和垂直领域中的表现仍存在提升空间&#xff0c;因此衍生出针对具体场景的微调训练需求。这些训练涵盖预训练&#xff08;PT&#xff09;、指令微调&#xff08;SFT&…

idea中 maven 本地仓库有jar包,但还是找不到,解决打包失败和无法引用的问题

1、删除本地仓库中的文件 进入本地仓库对应jar包文件目录中删除_remote.repositories文件和结尾为.lastUpdated的文件 2、回到IDEA刷新Maven 3、查看之前引用不了的jar是否引入成功

(33)课54--??:3 张表的 join-on 连接举例,多表查询总结。

&#xff08;112&#xff09;3 张表的 join-on 连接举例 &#xff1a; &#xff08;113&#xff09; 多表查询总结 &#xff1a; &#xff08;114&#xff09;事务 &#xff1a; &#xff08;115&#xff09; &#xff08;116&#xff09; &#xff08;117&#xff09; …