权限校验—接口检验

news2024/11/24 15:52:15

一、背景介绍

最近项目中要实现根据不同用户去划分不同的角色,而不同角色具备调用不同接口的权限这个功能。用户在调用接口时需要校验用户是否具有权限访问接口,防止外界恶意调用随意篡改


二、思路&方案

为什么要进行接口鉴权?

  1. 接口鉴权可以提供对接口访问的监控和追踪功能。通过记录和审计用户对接口的访问情况,可以及时发现异常行为和安全威胁,并采取相应的措施进行应对。
  2. 通过接口鉴权,可以限制对敏感数据的访问。只有具有相应权限的用户或应用程序才能获取敏感数据,从而保护数据的机密性和完整性。
  3. 接口鉴权可以实现对接口的细粒度访问控制。根据用户的身份、角色、权限等级等,可以控制用户对接口的不同操作和功能的访问权限,确保只有有权用户可以执行相应的操作。

接口鉴权是保证系统安全、数据保护和访问控制的重要机制,防止未经授权的访问、滥用和数据泄露,提高系统的安全性和可靠性。

@PerAuthorizre权限注解

作用:方法前拦截判断是否具备权限,用来控制被注解标记的类或方法是否能够被调用

好处

  1. 安全性增强:只有经过授权的用户才能执行带有 @PerAuthorizr 注解的代码,从而减少了潜在的安全漏洞和攻击风险。

  2. 标记权限:通过使用 @PerAuthorizr 注解,可以明确地标记哪些代码需要特定的权限才能执行。这有助于开发人员更好地了解代码的权限需求,并确保只有具有相应权限的用户或角色可以访问该代码。

底层实现

  1. 底层实现可能会使用 AOP 技术。通过 AOP,可以在代码执行之前或之后,根据注解的参数进行权限验证和授权操作。
  2. 可能会使用拦截器或过滤器来拦截请求,并进行权限验证和授权操作。拦截器或过滤器可以在请求到达目标代码之前对请求进行预处理,包括检查用户的权限和身份验证。
  3. 可能会使用缓存机制。通过缓存用户的权限信息,可以避免频繁地进行权限查询和验证,提高系统的响应速度。

使用

@PreAuthorize("")

调用别名为ss类的hasPermi方法,并传入参数

@ss注解

作用:自定义,定义了权限校验流程

结果:返回true则鉴权成功,false则返回403说明没有权限

使用

@ss.hasPermi('system:role:list')

调用别名为ss类的hasPermi方法,并传入参数

逻辑校验流程

第一步、定义@ss类,并添加hasPermi校验方法

  1.         获取传入用户的信息
  2.         判断用户信息的权限信息集合中是否含有定义的权限

第二步、在要鉴权的接口上添加@PreAuthorizez注解


三、过程

NS图

引入依赖

<!-- spring security 安全认证 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-core</artifactId>
    <version>5.5.8</version>
</dependency>

定义@ss类,并添加hasPermi校验方法

package com.example;

import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.util.Set;

/**
 * @BelongsPackage: com.example
 * @Description: 自定义权限实现
 * @Version: 1.0
 */
@Service("ss")
public class PermissionService {
    /** 所有权限标识 */
    private static final String ALL_PERMISSION = "*:*:*";


    /**
     * 验证用户是否具备某权限
     *
     * @param permission 权限字符串
     * @return 用户是否具备某权限
     */
    public boolean hasPermi(String permission) throws Exception {
        //判断是否传入权限字符
        if ( StringUtils.isEmpty(permission))
        {
            return false;
        }
        //获取用户信息
        LoginUser loginUser = SecurityUtils.getLoginUser();
        //判断是否有用户信息,或者用户信息中是否包含权限集合
        if ( StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getPermissions()))
        {
            return false;
        }
        //将权限设置到请求头中
        PermissionContextHolder.setContext(permission);
        //判断是否包含权限
        return hasPermissions(loginUser.getPermissions(), permission);
    }

    /**
     * 判断是否包含权限
     *
     * @param permissions 权限列表
     * @param permission 权限字符串
     * @return 用户是否具备某权限
     */
    private boolean hasPermissions(Set<String> permissions, String permission)
    {
        return permissions.contains(ALL_PERMISSION) || permissions.contains(StringUtils.trim(permission));
    }
}

字符串工具类

package com.example;

/**
 * @BelongsPackage: com.example
 * @Description: 字符串工具类
 * @Version: 1.0
 */
public  class StringUtils {
    /** 空字符串 */
    private static final String NULLSTR = "";

    /**
     * * 判断一个对象是否为空
     * @return true:为空 false:非空
     */
    public static boolean isNull(Object object)
    {
        return object == null;
    }

    /**
     * * 判断一个字符串是否为空串
     * @return true:为空 false:非空
     */
    public static boolean isEmpty(String str)
    {
        return isNull(str) || NULLSTR.equals(str.trim());
    }


    /**
     * 去空格
     */
    public static String trim(String str)
    {
        return (str == null ? "" : str.trim());
    }
}

权限信息

package com.example;

import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

/**
 * @BelongsPackage: com.example
 * @Description: TODO
 * @Version: 1.0
 */
public class PermissionContextHolder {
    private static final String PERMISSION_CONTEXT_ATTRIBUTES = "PERMISSION_CONTEXT";

    public static void setContext(String permission)
    {
        RequestContextHolder.currentRequestAttributes().setAttribute(PERMISSION_CONTEXT_ATTRIBUTES, permission,
                RequestAttributes.SCOPE_REQUEST);
    }

    public static String getContext()
    {
        return Convert.toStr(RequestContextHolder.currentRequestAttributes().getAttribute(PERMISSION_CONTEXT_ATTRIBUTES,
                RequestAttributes.SCOPE_REQUEST));
    }
}

安全服务工具类

package com.example;

import org.springframework.http.HttpStatus;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;

/**
 * @BelongsPackage: com.example
 * @Description: 安全服务工具类
 * @Version: 1.0
 */
public class SecurityUtils {
    /**
     * 获取用户
     **/
    public static LoginUser getLoginUser() throws Exception {
        try
        {
            return (LoginUser) getAuthentication().getPrincipal();
        }
        catch (Exception e)
        {
            throw new Exception("获取用户信息异常");
        }
    }

    /**
     * 获取Authentication
     */
    public static Authentication getAuthentication()
    {
        return SecurityContextHolder.getContext().getAuthentication();
    }
}

登录用户身份权限

package com.example;

import lombok.Data;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
import java.util.Set;

/**
 * @BelongsPackage: com.example
 * @Description: 登录用户身份权限
 * @Version: 1.0
 */
@Data
public class LoginUser implements UserDetails
{
    private static final long serialVersionUID = 1L;

    /**
     * 用户ID
     */
    private Long userId;

    /**
     * 部门ID
     */
    private Long deptId;

    /**
     * 用户唯一标识
     */
    private String token;

    /**
     * 登录时间
     */
    private Long loginTime;

    /**
     * 过期时间
     */
    private Long expireTime;

    /**
     * 登录IP地址
     */
    private String ipaddr;

    /**
     * 登录地点
     */
    private String loginLocation;

    /**
     * 浏览器类型
     */
    private String browser;

    /**
     * 操作系统
     */
    private String os;

    /**
     * 权限列表
     */
    private Set<String> permissions;


    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return null;
    }

    @Override
    public String getPassword() {
        return null;
    }

    @Override
    public String getUsername() {
        return null;
    }

    @Override
    public boolean isAccountNonExpired() {
        return false;
    }

    @Override
    public boolean isAccountNonLocked() {
        return false;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return false;
    }

    @Override
    public boolean isEnabled() {
        return false;
    }
}


四、总结

本文章对@PerAuthorizre注解结合项目具体如何进行鉴权进行了详细分析,我们在项目使用的过程中除了知道怎么用,也要知其所以然。

如果大家想要了解 spring sercurity+token安全机制是如何做的权限认证和授权,关于SpringSecurity如何集成JWT做的认证授权大家可以参考这篇博主的文章:SpringSecurity集成JWT认证框架_jwt spring security_哆木的博客-CSDN博客)

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

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

相关文章

几种常见的光纤接头有哪些?

名称: 光纤接头 光纤接头(optical fiber splice),将两根光纤永久地或可分离开地联结在一起,并有保护部件的接续部分,光纤接头是光纤的末端装置问题描述: 几种常见的光纤接头有哪些? 回答: 1.常见的光纤接头 LC 、SC 、FC 、ST、 MPO LC (Lucent connector) 小…

MySQL 事务原理:锁机制

文章目录 一、锁类型1.1 全局锁1.2 表级锁1.2.1 表锁1.2.2 元数据锁1.2.3 意向锁1.2.4 自增锁 1.3 行级锁1.3.1 记录锁1.3.2 间隙锁1.3.3 临键锁1.3.4 插入意向锁 1.4 锁的兼容性 二、锁的CUDP2.1 查询2.2 删除、更新2.3 插入 三、锁的对象四、并发死锁4.1 相反加锁顺序导致死锁…

监控Kafka的关键指标

Kafka 架构 上面绿色部分 PRODUCER&#xff08;生产者&#xff09;和下面紫色部分 CONSUMER&#xff08;消费者&#xff09;是业务程序&#xff0c;通常由研发人员埋点解决监控问题&#xff0c;如果是 Java 客户端也会暴露 JMX 指标。组件运维监控层面着重关注蓝色部分的 BROKE…

Redis 高频数据类型使用详解

目录 一、前言 二、Redis常用数据类型 2.1 常见的数据类型 三、String 类型 3.1 String 类型简介 3.2 String常用操作命令 3.2.1 String 操作命令实践 3.3 常用业务场景 3.3.1 session共享 3.3.2 登录失败计数器 3.3.3 限流 3.3.4 多线程安全控制 四、Hash类型 4…

【C++笔记】C++启航之为C语言填坑的语法

【C笔记】C启航之为C语言填坑的语法 一、命名空间1、为什么要引入命名空间&#xff1f;2、命名空间的基本用法3、展开命名空间4、命名空间的套娃5、命名空间的自动合并 二、缺省参数1、为什么要引入缺省参数&#xff1f;2、缺省参数的基本用法3、缺省的参数必须从右向左4、缺省…

为什么我们需要加快推进数字孪生技术?

数字孪生技术以其强大的潜力和应用前景&#xff0c;引起了各行各业的广泛关注和热切期待。那么&#xff0c;究竟为什么要加快推进数字孪生技术呢&#xff1f; 首先&#xff0c;数字孪生技术能够实现现实世界与虚拟世界的无缝连接&#xff0c;为各行业带来了前所未有的创新机遇…

Vue电商项目--VUE插件的使用及原理

图片懒加载 图片懒加载&#xff0c;就是图片延迟加载。只加载页面可视区域上的图片&#xff0c;等滚动到页面下面时&#xff0c;再加载对应视口上的图片 而在vue中有一个插件 vue-lazyload - npm (npmjs.com) npm i vue-lazyload 去使用他&#xff0c;这里我们引入了一张图片…

(九)人工智能应用--深度学习原理与实战--前馈神经网络实现MNST手写数字识别

目标: 识别手写体的数字,如图所示: 学习内容: 1、掌握MNIST数据集的加载和查看方法 2、熟练掌握Keras建立前馈神经网络的步骤【重点】 3、掌握模型的编译及拟合方法的使用,理解参数含义【重点】 4、掌握模型的评估方法 5、掌握模型的预测方法 6、掌握自定义图片的处理与预测 …

十分钟掌握使用 SolidJS 构建全栈 CRUD 应用程序

我们可以开始讨论 SolidJS&#xff0c;说它比React更好&#xff0c;但没有必要做这种比较。SolidJS只是众多前端框架之一&#xff0c;旨在在Web上快速创建数据驱动。那么&#xff0c;我们为什么要突出这个新孩子呢&#xff1f; 首先&#xff0c;我们不能忽视SolidJS不使用虚拟…

嗅探抓包工具,解决线上偶现问题来不及抓包的情况阅读目录

目录 背景 实现思路 具体实现 Python 抓包 总结 资料获取方法 背景 测试群里经常看到客户端的同学反馈发现了偶现Bug&#xff0c;但是来不及抓包&#xff0c;最后不了了之&#xff0c;最近出现得比较频繁&#xff0c;所以写个小脚本解决这个问题。 实现思路 之前写过一个…

免费实用的日记应用:Day One for Mac中文版

Day One for Mac是一款运行在Mac平台上的日记软件&#xff0c;你可以使用Day One for mac通过快速菜单栏条目、提醒系统和鼓舞人心的信息来编写更多内容&#xff0c;day one mac版还支持Dropbox同步功能&#xff0c;想要day one mac中文免费版的朋友赶紧来试试吧&#xff01; …

IPC之一:使用匿名管道进行父子进程间通信的例子

IPC 是 Linux 编程中一个重要的概念&#xff0c;IPC 有多种方式&#xff0c;本文主要介绍匿名管道(又称管道、半双工管道)&#xff0c;尽管很多人在编程中使用过管道&#xff0c;但一些特殊的用法还是鲜有文章涉及&#xff0c;本文给出了多个具体的实例&#xff0c;每个实例均附…

Leetcode.1316 不同的循环子字符串

题目链接 Leetcode.1316 不同的循环子字符串 rating : 1837 题目描述 给你一个字符串 text &#xff0c;请你返回满足下述条件的 不同 非空子字符串的数目&#xff1a; 可以写成某个字符串与其自身相连接的形式&#xff08;即&#xff0c;可以写为 a a&#xff0c;其中 a 是…

服务器感染了LockBit 3.0勒索病毒,如何确保数据文件完整恢复?

引言&#xff1a; 在数字时代&#xff0c;恶意软件的威胁变得愈发严峻&#xff0c;而LockBit 3.0勒索病毒则是其中的顶尖恶势力之一。其先进的加密技术和毫不留情的勒索手段&#xff0c;使无数人蒙受损失。然而&#xff0c;我们不应束手无策。本文91数据恢复将带您深入了解Loc…

AndroidStudio通过Profiler查找内存泄漏

Fragment内存泄漏&#xff1a; AndroidStudio --> Profiler --> 勾选 show nearest Gc root only&#xff0c;然后查看非weakreference的引用&#xff08;weakreference是不会导致内存泄漏的&#xff09;&#xff0c;往下就能找自己项目里写的代码&#xff0c;一般此处…

旷视科技AIoT软硬一体化走向深处,生态和大模型成为“两翼”?

齐奏AI交响曲的当下&#xff0c;赛道玩家各自精彩。其中&#xff0c;被称作AI四小龙的商汤科技、云从科技、依图科技、旷视科技已成长为业内标杆&#xff0c;并积极追赶新浪潮。无论是涌向二级市场还是布局最新风口大模型&#xff0c;AI四小龙谁都不甘其后。 以深耕AIoT软硬一…

ASCP系列电气防火限流式保护器在养老院的应用-安科瑞黄安南

摘要&#xff1a;2020年&#xff0c;我国65岁及以上老年人口数量为1.91亿&#xff0c;老龄化率达到13.5%。总体来看&#xff0c;大部分省市的养老机构数量还较少。养老设施的建设与民生息息相关&#xff0c;养老院的电气安全也非常重要。如果发生电气火灾&#xff0c;对于行动不…

【多模态】24、开放词汇学习到底是什么?

文章目录 一、什么是开放词汇学习二、开放词汇学习的测评和数据集三、开放词汇目标检测3.1 Region-Aware Training3.2 Pseudo-Labeling3.3 Knowledge Distillation-Based3.4 Transfer Learning-Based3.5 总结3.6 效果 参考论文&#xff1a;A Survey on Open-Vocabulary Detecti…

Vue3 事件处理简单应用

去官网学习→事件处理 | Vue.js 运行示例&#xff1a; 代码&#xff1a;HelloWorld.vue <template><div class"hello"><h1>Vue 事件处理</h1><button v-on:click"numb 1">点击加1-----{{ numb }}</button><br/&…

独家揭秘Linux内核栈:内核态的奇妙之处和与用户态的差异

理解Linux内核栈可以从以下几个方面来考虑&#xff1a;内核态与用户态&#xff1a;在阅读Linux内核及相关资料时&#xff0c;需要明确它所描述的是内核态还是用户态的内容。这有助于理解所讨论的是在哪个执行环境下进行的操作。进程与线程的描述&#xff1a;用户态的进程和线程…