Java-Secruity-2

news2024/11/24 10:56:50

 可以先看这篇文章

Secruity-1👈

1、授权

1.1 权限管理

在日常使用的系统中都会涉及到权限相关的操作,管理员有管理员的操作,用户有用户的操作,不同的用户可以使用不同的功能,这需要使用到权限管理。

所以在写接口的时候需要在后台进行用户权限的判断,判断当前用户是否有相应的权限,必须具有所需权限才能进行相应的操作。

image-20221104151126316

RBAC权限模型

user表

menu表

role表

role_menu表

user_role表
 sql语句

通过user_id关联user_role得到用户的role_id

通过role_id关联role得到角色对应的信息

通过role_id关联role_menu得到menu_id

通过menu_id关联menu得到权限的具体信息

2.2 授权实现

2.2.1 设置资源权限

  • 启动类开启配置
    @EnableGlobalMethodSecurity(prePostEnabled = true)
  • 注解配置
    @RequestMapping
    // 设置这个接口需要system:class:list权限,这个可以在数据库的sys_menu中查找
    @PreAuthorize("hasAnyAuthority('在数据库设置的权限标识')")
    public String queryAll() {
        System.out.println("queryAll");
        return "user";
    }
    重写LoginUser里的getAuthorities
  • // 存储每个用户的权限信息
        private List<String> permissions;
    
    
    
        @JsonIgnore// 不手动添加的话后去反序列化会出现异常
        /*
        authorities用于在底下的getAuthorities返回
        登入成功后,会把用户信息存在redis里java的数据是以对象的形式表示
        redis的数据表示格式和java不一样,需要进行数据格式的转化
         */
                // 权限集合需要转换成这种类型的Security才能判断
        List<GrantedAuthority> authorities = new ArrayList<>();
    
        @Override
        public Collection<? extends GrantedAuthority> getAuthorities() {
    
            //现在要做的就是把上面定义的authorities放入每个用户的权限信息
            for(String permission:permissions) {
                authorities.add(new SimpleGrantedAuthority(permission));
            }
            return authorities;
        }
    mapper
  • public interface UserMapper extends BaseMapper<MsUser> {
    
        List<String> getPermissions(Long userId);
    
    }
    xml
  • <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.example.demo.mapper.UserMapper">
    
        <select id="getPermissions" resultType="string">
            SELECT t5.key FROM user t1
                JOIN user_role t2 on t1.id = t2.user_id
                JOIN role t3 ON t3.role_id = t2.role_id
                JOIN role_menu t4 ON t4.role_id = t3.role_id
                JOIN menu t5 ON t5.menu_id = t4.menu_id
            WHERE t1.id = #{userId}
        </select>
    
    
    </mapper>
    
    UserDetailsServiceImpl中获取权限信息
  • 
    
    // 重写了UserDetailsService,控制台就没有打印生成的密码。因为我们自定义了登录流程
    @Service
    public class UserDetailsServiceImpl implements UserDetailsService {
    
        @Autowired
        private IUserService userService;
        @Autowired
        private UserMapper userMapper;
    
        // UserDetails: security存放登录用户信息
        @Override
        public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
            System.out.println("loadUserByUsername");
            LambdaQueryWrapper<MsUser> qw = new LambdaQueryWrapper<>();
            qw.eq(MsUser::getUsername, username);
            // 根据账号查询用户信息
            MsUser msUser = userService.getOne(qw);
    
            // TODO: 统一处理异常
            if(msUser == null) {
                throw new RuntimeException("账号不存在");
            }
    
            LoginUser loginUser = new LoginUser();
            loginUser.setMsUser(msUser);
    
            //这里底下是登录成功要做的事
            
            // 获取权限信息
            List<String> permissions = userMapper.getPermissions(msUser.getId());
            // 将权限信息装到loginUser对象
            loginUser.setPermissions(permissions);
    
            return loginUser;
        }
    
    }
    
    自定义权限校验
  • @Component("ss")
    //类名方法名怎么定义都行
    public class MyExpressionUtil {
    
        //判断当前用户有没有当前方法上的标识
        public boolean myAuthority(String key) {
    
            //SecurityContextHolder.getContext()获取用户信息
            // 获取用户的权限列表
            Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
    
            // 获取到登录的用户
            LoginUser loginUser = (LoginUser) authentication.getPrincipal();
    
            // 拿到该用户的权限
            List<String> permissions = loginUser.getPermissions();
    
            return permissions.contains(key);
        }
    
    
    控制层的方法上加上注解
  •  @GetMapping("/test1")
        @PreAuthorize("@ss.myAuthority('t1')")
        public String test1() {
            System.out.println("test1");
            return "test1";
        }

    3.1 简介

    前面写的接口,如果有错误异常等,前端看不见也不知道什么问题,所以一般会做一个统一的错误处理,可以使用SpringSecurity的异常处理机制。

    在SpringSecurity中,如果我们在认证或者授权的过程中出现了异常会被ExceptionTranslationFilter捕获到。在ExceptionTranslationFilter中会去判断是认证失败还是授权失败出现的异常。

    如果是认证过程中出现的异常会被封装成AuthenticationException然后调用AuthenticationEntryPoint对象的方法去进行异常处理。

    如果是授权过程中出现的异常会被封装成AccessDeniedException然后调用AccessDeniedHandler对象的方法去进行异常处理。

    所以如果我们需要自定义异常处理,我们只需要自定义AuthenticationEntryPointAccessDeniedHandler然后配置给SpringSecurity即可。

统一返回数据Result 

@Data
public class R<T> {

    private String msg;

    private Integer code;

    private T data;

    public R() {
    }

    public R(String msg, Integer code, T data) {
        this.msg = msg;
        this.code = code;
        this.data = data;
    }

    public static R success() {
        return new R("操作成功!!", 200, null);
    }

    public static <T> R success(T data) {
        return new R("操作成功!!", 200, data);
    }

    public static R error() {
        return new R("操作失败!!", 500, null);
    }

    public static R error(String msg, Integer code) {
        return new R(msg, code, null);
    }

    public static R to(int rs) {
        return rs > 0 ? R.success() : R.error();
    }
    
}

捕捉认证失败

//捕捉认证过程出现的异常(token异常)
@Component
public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        response.setContentType("application/json;charset=utf8");
        response.getWriter().write(JSON.toJSONString(R.error("认证失败", 401)));
    }
}

捕捉授权失败

//捕捉授权失败的异常(权限异常)
@Component
public class AccessDeniedHandlerImpl implements AccessDeniedHandler {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
        response.setContentType("application/json;charset=utf8");
        response.getWriter().write(JSON.toJSONString(R.error("没有权限", 403)));
    }
}
3.3 配置给SpringSecurity

修改configure方法(Security配置的过滤器都要加到这里)

@Autowired
private AuthenticationEntryPointImpl authenticationEntryPoint;
@Autowired
private AccessDeniedHandlerImpl accessDeniedHandler;
​
// 配置异常处理器
http
    .exceptionHandling()
    .authenticationEntryPoint(authenticationEntryPoint)
    .accessDeniedHandler(accessDeniedHandler);

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

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

相关文章

openGauss学习笔记-168 openGauss 数据库运维-备份与恢复-导入数据-使用gs_restore命令导入数据

文章目录 openGauss学习笔记-168 openGauss 数据库运维-备份与恢复-导入数据-使用gs_restore命令导入数据168.1 操作场景168.2 操作步骤168.3 示例 openGauss学习笔记-168 openGauss 数据库运维-备份与恢复-导入数据-使用gs_restore命令导入数据 168.1 操作场景 gs_restore是…

PyQt6 信号与槽

锋哥原创的PyQt6视频教程&#xff1a; 2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~共计51条视频&#xff0c;包括&#xff1a;2024版 PyQt6 Python桌面开发 视频教程(无废话版…

makefile例子

1、目录结构 2、文件 2.1、 test.h extern void test(void); 2.2 、test.c #include <stdio.h>void test(void) {printf("Hello world!\n"); }2.3 、main.c #include "test.h"int main(void) {test();return 0; }2.4、makefile TEST_DIR : $(s…

【QT表格-6】QTableWidget的currentCellChanged实现中途撤销

背景&#xff1a; 【QT表格-1】QStandardItem的堆内存释放需要单独delete&#xff0c;还是随QStandardItemModel的remove或clear自动销毁&#xff1f;-CSDN博客 【QT表格-2】QTableWidget单元格结束编辑操作endEditting_qtablewidget 单元格编辑事件-CSDN博客 【QT表格-3】Q…

做一个类似东郊到家系统都有哪些功能特点?

随着科技的发展&#xff0c;人们的生活方式也在不断变化&#xff0c;在快节奏的生活中&#xff0c;身心疲惫的人们需要一种快速有效的方式来缓解压力。同城预约上门按摩小程序就是为满足这种需求而诞生的。用户可以通过小程序&#xff0c;方便地预约按摩服务&#xff0c;无需浪…

力扣日记12.21【二叉树篇】98. 验证二叉搜索树

力扣日记&#xff1a;【二叉树篇】98. 验证二叉搜索树 日期&#xff1a;2023.12.21 参考&#xff1a;代码随想录、力扣 98. 验证二叉搜索树 题目描述 难度&#xff1a;中等 给你一个二叉树的根节点 root &#xff0c;判断其是否是一个有效的二叉搜索树。 有效 二叉搜索树定义…

24_28-Golang函数详解

**Golang **函数详解 主讲教师&#xff1a;&#xff08;大地&#xff09; 合作网站&#xff1a;www.itying.com** **&#xff08;IT 营&#xff09; 我的专栏&#xff1a;https://www.itying.com/category-79-b0.html 1、函数定义 :::info 函数是组织好的、可重复使用的、用…

云渲染如何使用?其实很简单,只需3步就搞定了!

很多人第一次接触云渲染&#xff0c;对云渲染不了解&#xff0c;不知道云渲染怎么用&#xff0c;其实很简单&#xff0c;只需要3步就搞定了。 第一步&#xff1a;下载并安装客户端 到炫云官网下载客户端&#xff0c;下载完直接点击安装就可以&#xff0c;炫云的效果图渲染和动…

【代码规范】统一参数校验、结果返回

统一参数校验&#xff1a; 在编写Controller层的代码时&#xff0c;时常会有这种情况出现&#xff1a; RestController RequestMapping("/user") public class UserController {Resourceprivate UserService userService;PostMapping("register")public S…

【基础知识】大数据组件YARN简述

YARN是一个分布式的资源管理系统。 YARN是Hadoop系统的核心组件&#xff0c;主要功能包括负责在Hadoop集群中的资源管理&#xff0c;负责对作业进行调度运行以及监控。 ResourceManager 负责集群的资源管理与调度&#xff0c;为运行在YARN上的各种类型作业分配资源。 非HA集…

设计模式03结构型模式

结构型模式 参考网课:黑马程序员Java设计模式详解 博客笔记 https://zgtsky.top/ 结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式&#xff0c;前者采用继承机制来组织接口和类&#xff0c;后者釆用组合或聚合来组合对象。 由于…

通过讯飞 API 接口用 Vue 实现实时语音转写

通过讯飞 API 接口用 Vue 实现实时语音转写 项目地址 前言 本项目中实时语音能够转写的最大时间为 60 s&#xff0c; 这个数据也是由 API 提供方给限制掉的 为什么我会需要这个点击按钮以后能够实现实时语音的转写呢&#xff0c;因为被课程所迫&#xff0c;选了这个方向就必…

linux 性能优化-内存优化

CPU 管理一样&#xff0c;内存管理也是操作系统最核心的功能之一。内存主要用来存储系统和应 用程序的指令、数据、缓存等。 1.内存原理 1.1.内存映射 1.1.1.日常生活常说的内存是什么? 我的笔记本电脑内存就是 8GB 的这个内存其实是物理内存物理内存也称为主存&#xff0…

Java最全面试题专题---5、Spring面试题(1)

Spring概述&#xff08;10&#xff09; 什么是spring? Spring是一个轻量级Java开发框架&#xff0c;最早有Rod Johnson创建&#xff0c;目的是为了解决企业级应用开发的业务逻辑层和其他各层的耦合问题。它是一个分层的JavaSE/JavaEE full-stack&#xff08;一站式&#xff…

联合体(C语言)

小伙伴们又来学习知识啦~&#xff0c;今天我要给大家介绍一下联合体的使用&#xff0c;话不多说&#xff0c;我们开始今天的正题吧&#xff01; 联合体的介绍 C语言的联合体&#xff08;union&#xff09;是一种特殊的数据类型&#xff0c;它可以在同一内存空间中存储不同的数…

龙迅LT86102UXE HDMI一分二HDMI,支持音频剥离,支持4K60HZ

描述&#xff1a; 龙迅 LT86102UXE HDMI2.0 分路器具有符合 HDMI2.0/1.4 规范的 1&#xff1a;2 分路器、最大 6Gbps 高速数据速率、自适应均衡 RX 输入和预加重 TX 输出&#xff08;用于支持长电缆应用&#xff09;、内部 TX 通道交换以实现灵活的 PCB 布线。 LT86102UXE HDM…

机器学习之线性回归(Linear Regression)附代码

概念 线性回归(Linear Regression)是机器学习中的一种基本的监督学习算法,用于建立输入变量(特征)与输出变量(目标)之间的线性关系。它假设输入变量与输出变量之间存在线性关系,并试图找到最佳拟合线来描述这种关系。 在简单线性回归中,只涉及两个变量:一个是自变量…

Ubuntu 常用命令之 passwd 命令用法介绍

&#x1f4d1;Linux/Ubuntu 常用命令归类整理 在Ubuntu系统中&#xff0c;passwd命令用于更改用户的密码。系统管理员可以使用此命令更改任何用户的密码&#xff0c;而普通用户只能更改自己的密码。 passwd命令的参数如下 -l, --lock&#xff1a;锁定密码&#xff0c;使账户…

Apache+PHP环境配置 手动配置

准备工作&#xff0c;在G盘新建一个WAMP目录 1.获取Apache 打开下载地址Apache VS17 binaries and modules download&#xff0c;下载 httpd-2.4.58-win64-VS17.zip 将下载好的httpd-2.4.58-win64-VS17.zip拷贝到G:\WAMP目录下并解压到当前目录&#xff0c;得到Apache24目录 …

石墨匣钵,预计到2025年将达到3.973亿美元

石墨匣钵是陶瓷和耐火材料工业用于烧制和烧结各种材料的高温容器。在陶瓷产品需求增加和耐火材料行业增长的推动下&#xff0c;全球石墨匣钵市场在过去几年出现了显着增长。2020 年全球石墨匣钵市场价值为 3.039 亿美元&#xff0c;预计到 2025 年将达到 3.973 亿美元&#xff…