SpringSecurity5.7+最新案例 -- 授权 --

一、前提

书接上回 SpringSecurity5.7+最新案例 – 用户名密码+验证码+记住我······

本文 继续处理SpringSecurity授权 …

目前由 难 -> 简,即自定义数据库授权,注解授权,config配置授权

二、自定义授权

0. 数据准备

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `age` int(11) NULL DEFAULT NULL,
  `address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `phone` varchar(13) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `passwd` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `pwd` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `role` json NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of user
-- ----------------------------
BEGIN;
INSERT INTO `user` VALUES (1, 'a', 35, '太原', '11', '$2a$10$tbFi2xQwHQcjIp4jt5eGZ..CER7ws.Pzg9RiBM1tTGH1omkNprXqC', '123', '[{\"name\": \"系统管理员\", \"role\": \"ROLE_ADMIN\"}, {\"name\": \"普通用户\", \"role\": \"ROLE_USER\"}]');
INSERT INTO `user` VALUES (2, 'b', 51, '沧州', '22', '$2a$10$c8.tVJ36cqcTHV/lGugyc.uf3ft9nQ4jNJpqhhWESpAv7uOspDg1K', '456', '[{\"name\": \"普通用户\", \"role\": \"ROLE_USER\"}]');
INSERT INTO `user` VALUES (3, 'c', 43, '兖州', '33', '$2a$10$akbjbzIjdGjy3/4sUvizae11LvEZXxLUPO0n.4x1NfPupCJYI4aUm', '789', '[{\"name\": \"游客\", \"role\": \"ROLE_GUEST\"}]');
COMMIT;



-- ----------------------------
-- Table structure for menu
-- ----------------------------
DROP TABLE IF EXISTS `menu`;
CREATE TABLE `menu`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `pattern` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `role` json NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of menu
-- ----------------------------
BEGIN;
INSERT INTO `menu` VALUES (1, '/admin/**', '[{\"name\": \"系统管理员\", \"role\": \"ROLE_ADMIN\"}]');
INSERT INTO `menu` VALUES (2, '/user/**', '[{\"name\": \"普通用户\", \"role\": \"ROLE_USER\"}]');
INSERT INTO `menu` VALUES (3, '/guest/**', '[{\"name\": \"普通用户\", \"role\": \"ROLE_USER\"}, {\"name\": \"游客\", \"role\": \"ROLE_GUEST\"}]');
COMMIT;

SET FOREIGN_KEY_CHECKS = 1;

1. 说明

​ 由于使用的是jpa,以及在mysql中使用到了json数据,所以先在项目中引入json支持, 使用 mybatis 的绕行

<dependency>
    <groupId>com.vladmihalcea</groupId>
    <artifactId>hibernate-types-52</artifactId>
    <version>2.3.5</version>
</dependency>

2. UserDstail变化

image-20230807174353840

3. SecurityConfig中配置变化如下

image-20230807173743413

4. 实现 FilterInvocationSecurityMetadataSource

@Component
public class MySecurityMetadataSource implements FilterInvocationSecurityMetadataSource {

    // 这里注入的查询menu的接口类
    final MenuRepository menuRepository;

    public MySecurityMetadataSource(MenuRepository menuRepository) {
        this.menuRepository = menuRepository;
    }

    AntPathMatcher antPathMatcher = new AntPathMatcher();

    @Override
    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
        String requestURI = ((FilterInvocation) object).getRequest().getRequestURI();
        // 获取无需权限就能访问的公共资源, 不需权限的访问,直接返回,不需要在进入数据量中查询
        String[] pubSource = PublicRequestSource.get();
        for (String source : pubSource) {
            if (antPathMatcher.match(source, requestURI)) {
                return null;
            }
        }
        // 如果要访问的资源不在公共资源里面,则去数据库中查询,然后创建访问权限
        List<MenuEntity> allMenu = menuRepository.findAll();
        for (MenuEntity menu : allMenu) {
            if (antPathMatcher.match(menu.getPattern(), requestURI)) {
                List<RoleEntity> role = menu.getRole();
                String[] roles = role.stream().map(RoleEntity::getRole).toArray(String[]::new);
                return SecurityConfig.createList(roles);
            }
        }
        return null;
    }

    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return null;
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return FilterInvocation.class.isAssignableFrom(clazz);
    }
}

5. 配置公共资源

​ – 也可以写在配置文件中

public class PublicRequestSource {

    public static String[] get() {
        return new String[]{
                "/hello", "/login"
        };
    }

}

6. 实现ObjectPostProcessor

@Component
public class MyObjectPostProcessor implements ObjectPostProcessor<FilterSecurityInterceptor> {

    @Resource
    private MySecurityMetadataSource mySecurityMetadataSource;

    @Override
    public <O extends FilterSecurityInterceptor> O postProcess(O object) {
        object.setSecurityMetadataSource(mySecurityMetadataSource);
        // 打开公共资源访问权限
        object.setRejectPublicInvocations(false);
        return object;
    }

}

7. 创建TestController测试请求接口权限

// 实际这里会写在多个controller类下,这里为了测试
@RestController
public class TestController {
    @GetMapping("/admin/hello")
    public String admin() {
        return "hello admin";
    }

    @GetMapping("/user/hello")
    public String user() {
        return "hello user";
    }

    @GetMapping("/guest/hello")
    public String guest() {
        return "hello guest";
    }

    @GetMapping("/hello")
    public String hello() {
        return "hello";
    }

}

8. 然后用postman登录测试接口把

image-20230807174918920

image-20230807174954184

嗯,其它的就不测试了…

三、注解授权

1. 开启全局授权

@SpringBootApplication
// 开启全局授权(详细解释如下)
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
public class SplitBackWeb03Application {
    public static void main(String[] args) {
        SpringApplication.run(SplitBackWeb03Application.class);
    }
}
  • perPostEnabled: 开启 Spring Security 提供的四个权限注解,@PostAuthorize、@PostFilter、@PreAuthorize 以及@PreFilter。
  • securedEnabled: 开启 Spring Security 提供的 @Secured 注解支持,该注解不支持权限表达式
  • jsr250Enabled: 开启 JSR-250 提供的注解,主要是@DenyAll、@PermitAll、@RolesAll 同样这些注解也不支持权限表达式
# 以上注解含义如下:
- @PostAuthorize: 在目前标方法执行之后进行权限校验。
- @PostFiter: 在目标方法执行之后对方法的返回结果进行过滤。
- @PreAuthorize:在目标方法执行之前进行权限校验。
- @PreFiter:在目前标方法执行之前对方法参数进行过滤。
- @Secured:访问目标方法必须具各相应的角色。
- @DenyAll:拒绝所有访问。
- @PermitAll:允许所有访问。
- @RolesAllowed:访问目标方法必须具备相应的角色。

这些基于方法的权限管理相关的注解,一般来说只要设置 prePostEnabled=true 就够用了。

2. 注意事项

当开启了开启全局授权后,无需额外配置(即SecurityConfig最简如下),当然,也可以和自定义授权一起使用(但不推荐)

httpSecurity.formLogin().and().csrf().disable();

3. 创建测试controller类

@RestController
@RequestMapping("/hello")
public class AuthorizeMethodController {

    // 当角色为 ADMIN 并且 认证的用户名为“a”时,才允许访问,否则403
    @PreAuthorize("hasRole('ADMIN') and authentication.name=='a'")
    @GetMapping
    public String hello() {
        return "hello";
    }

    // 当认证的用户名 和 参数中传递的用户名 一致 时,才允许访问,否则403
    @PreAuthorize("authentication.name==#name")
    @GetMapping("/name")
    public String hello(String name) {
        return "hello:" + name;
    }

    // 过滤作用,如传递的UserList id为1,2,3的对象,则后台实际收到的是id为1,3的对象的数据
    // filterTarget 必须是数组 集合 类型
    @PreFilter(value = "filterObject.id%2!=0",filterTarget = "users")
    @PostMapping("/users")
    public void addUsers(@RequestBody List<User> users) {
        System.out.println("users = " + users);
    }

    // 认证作用,当参数中的id=1的时候,可以返回相应的数据,否则403
    @PostAuthorize("returnObject.id==1")
    @GetMapping("/userId")
    public User getUserById(Integer id) {
        return new User(id, "mose");
    }

    // 过滤作用,如结果集中的UserList id为1,2,3的对象,则返回实际的对象只有id 为 2 的对象
    // 返回数据 最好是 数组 或者集合,不然无效
    @PostFilter("filterObject.id%2==0")
    @GetMapping("/lists")
    public List<User> getAll() {
        return userService.findAll();
    }

    // 只能判断角色,当角色为 ROLE_USER 可访问
    @Secured({"ROLE_USER"}) 
    @GetMapping("/secured")
    public User getUserByUsername() {
        return new User(99, "secured");
    }

    // 只能判断角色,当角色具有其中一个即可
    @Secured({"ROLE_ADMIN","ROLE_USER"}) 
    @GetMapping("/username")
    public User getUserByUsername2(String username) {
        return new User(99, username);
    }

    // 允许所有
    @PermitAll
    @GetMapping("/permitAll")
    public String permitAll() {
        return "PermitAll";
    }

    // 拒绝所有
    @DenyAll
    @GetMapping("/denyAll")
    public String denyAll() {
        return "DenyAll";
    }

    // 角色判断,当具有其中一个角色即可
    @RolesAllowed({"ROLE_ADMIN","ROLE_USER"}) 
    @GetMapping("/rolesAllowed")
    public String rolesAllowed() {
        return "RolesAllowed";
    }
}

四、配置授权

1. 在securityConfig中配置即可,如下

httpSecurity.authorizeHttpRequests()
        .antMatchers("/admin/**").hasRole("ADMIN")
        .antMatchers("/user/**").hasAnyRole("USER", "ADMIN")
        .antMatchers("/guest").hasRole("GUEST")
        .anyRequest().authenticated()
        .and().formLogin()
        .and().csrf().disable();

2. 解释

方法说明
hasAuthority(String authority)当前用户是否具备指定权限
hasAnyAuthority(String… authorities)当前用户是否具备指定权限中任意一个
hasRole(String role)当前用户是否具备指定角色
hasAnyRole(String… roles);当前用户是否具备指定角色中任意一个
permitAll();放行所有请求/调用
denyAll();拒绝所有请求/调用
isAnonymous();当前用户是否是一个匿名用户
isAuthenticated();当前用户是否已经认证成功
isRememberMe();当前用户是否通过 Remember-Me 自动登录
isFullyAuthenticated();当前用户是否既不是匿名用户又不是通过 Remember-Me 自动登录的
hasPermission(Object targetId, Object permission);当前用户是否具备指定目标的指定权限信息
hasPermission(Object targetId, String targetType, Object permission);当前用户是否具备指定目标的指定权限信息

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

CentOS软件包管理rpm、yum

一、软件包概述 Linux常见软件包分为两种&#xff0c;分别是源代码包、二进制文件包。源代码包是没有经过编译的包&#xff0c;需要经过GCC、C编译器编译才能运行&#xff0c;文件内容包含源代码文件&#xff0c;通常以.tar.gz、.zip、.rar结尾&#xff1b;二进制包无需编译&am…

APP外包开发的开发语言对比

在开发iOS APP时有两种语言可以选择&#xff0c;Swift&#xff08;Swift Programming Language&#xff09;和 Objective-C&#xff08;Objective-C Programming Language&#xff09;&#xff0c;它们是两种不同的编程语言&#xff0c;都被用于iOS和macOS等苹果平台的软件开发…

pytorch学习——卷积神经网络——以LeNet为例

目录 一.什么是卷积&#xff1f; 二.卷积神经网络的组成 三.卷积网络基本元素介绍 3.1卷积 3.2填充和步幅 3.2.1填充&#xff08;Padding&#xff09; 填充是指在输入数据周围添加额外的边界值&#xff08;通常是零&#xff09;&#xff0c;以扩展输入的尺寸。填充可以在卷…

Dockerfile构建Tomcat镜像

准备apache包和jdk并解压 [rootlocalhost tomcat]# ll 总用量 196728 -rw-r--r--. 1 root root 9690027 7月 17 2020 apache-tomcat-8.5.40.tar.gz -rw-r--r--. 1 root root 674 8月 2 20:19 Dockerfile -rw-r--r--. 1 root root 191753373 7月 17 2020 jdk-8u191-…

【Python基础教程】super()函数的正确使用方法

前言 大家早好、午好、晚好吖 ❤ ~欢迎光临本文章 1.super(本身类名,self).方法名(参数)这样就可以调用父类的方法和参数了,super()内也可不加参数 2.规律是super是按调用的次序执行&#xff0c;super后面的语句是逆向执行的。 有2段示例代码&#xff0c;不同的在于value有没…

基于短信宝API零代码实现短信自动化业务

场景描述&#xff1a; 基于短信宝开放的API能力&#xff0c;实现在特定事件&#xff08;如天气预警&#xff09;或定时自动发送短信&#xff08;本文以定时群发短信为例&#xff09;。通过Aboter平台如何实现呢&#xff1f; 使用方法&#xff1a; 首先创建一个IPaaS流程&…

解决Vue3 使用Element-Plus导航刷新active高亮消失

解决Vue3 使用Element-Plus导航刷新后active高亮消失的问题 启用路由模式会在激活导航时以 index 作为 path 进行路由跳转 使用 default-active 来设置加载时的激活项。 接下来打印一下选中项index和index路径&#xff0c; 刷新也是没有任何问题的&#xff0c;active不会消失…

python+django+mysql项目实践二(前端及数据库)

python项目实践 环境说明&#xff1a; Pycharm 开发环境 Django 前端 MySQL 数据库 Navicat 数据库管理 前端模板 添加模板 在templates下创建 views文件中添加 创建数据库 连接数据库 在setting文件中进行配置 创建表

SDXL-Stable Diffusion改进版

文章目录 1. 摘要2. 算法&#xff1a;2.1 结构&#xff1a;2.2 微小的条件机制2.3 多宽高比训练2.4 改进自编码器2.5 所有组合放到一起2.6 主流方案比较 3. 未来工作4. 限制 论文&#xff1a; 《SDXL: Improving Latent Diffusion Models for High-Resolution Image Synthesis…

APP外包开发的android开发模式

开发 Android 应用有多种方法&#xff0c;每种方法都有其优势和适用场景。综合考虑各自的特点&#xff0c;你可以根据项目的需求和团队的技能选择最合适的开发方法。今天和大家分享几种常见的开发方法以及它们之间的对比&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公…

NeRF-SLAM: Real-Time Dense Monocular SLAM with Neural Radiance Fields 论文阅读

论文信息 题目&#xff1a;NeRF-SLAM: Real-Time Dense Monocular SLAM with Neural Radiance Fields 作者&#xff1a;Antoni Rosinol, John J. Leonard&#xff0c; Luca Carlone 代码&#xff1a;https://github.com/ToniRV/NeRF-SLAM 来源&#xff1a;arxiv 时间&#xff…

安装element-plus报错:Conflicting peer dependency: eslint-plugin-vue@7.20.0

VSCode安装element-plus报错&#xff1a; D:\My Programs\app_demo>npm i element-plus npm ERR! code ERESOLVE npm ERR! ERESOLVE could not resolve npm ERR! npm ERR! While resolving: vue/eslint-config-standard6.1.0 npm ERR! Found: eslint-plugin-vue8.7.1 npm E…

机器学习实战1-kNN最近邻算法

文章目录 机器学习基础机器学习的关键术语 k-近邻算法&#xff08;KNN&#xff09;准备&#xff1a;使用python导入数据实施kNN分类算法示例&#xff1a;使用kNN改进约会网站的配对效果准备数据&#xff1a;从文本文件中解析数据分析数据准备数据&#xff1a;归一化数值测试算法…

Go语言并发编程(千锋教育)

Go语言并发编程&#xff08;千锋教育&#xff09; 视频地址&#xff1a;https://www.bilibili.com/video/BV1t541147Bc?p14 作者B站&#xff1a;https://space.bilibili.com/353694001 源代码&#xff1a;https://github.com/rubyhan1314/go_goroutine 1、基本概念 1.1、…

鉴源论坛·观擎丨浅谈操作系统的适航符合性(上)

作者 | 蔡喁 上海控安可信软件创新研究院副院长 版块 | 鉴源论坛 观擎 社群 | 添加微信号“TICPShanghai”加入“上海控安51fusa安全社区” 01 源头和现状​​​​​​​ 在越来越多的国产机载系统研制中&#xff0c;操作系统软件的选择对后续开展研制以及适航举证活动带来…

码云 Gitee + Jenkins 配置教程

安装jdk 安装maven 安装Jenkins https://blog.csdn.net/minihuabei/article/details/132151292?csdn_share_tail%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22132151292%22%2C%22source%22%3A%22minihuabei%22%7D 插件安装 前往 Manage Jen…

基于Windows手动编译openssl和直接安装openssl

零、环境 win10-64位 VS2019 一、手动编译 前言&#xff1a;对于一般的开发人员而言&#xff0c;在 openssl 上下载已经编译好的 openssl 库&#xff0c;然后直接拿去用即可&#xff0c;&#xff0c;不用手动编译&#xff0c;{见下文直接安装}。。。对于一些开发人员&#…

Jmeter录制HTTPS脚本

Jmeter录制HTTPS脚本 文章目录 添加“HTTP代理服务器”设置浏览器代理证书导入存在问题 添加“HTTP代理服务器” 设置浏览器代理 保持端口一致 证书导入 点击一下启动让jmeter自动生成证书&#xff0c;放在bin目录下&#xff1a; 打开jmeter的SSL管理器选择刚刚生成的证书&…

# 关于Linux下的parted分区工具显示起始点为1049kB的问题解释

关于Linux下的parted分区工具显示起始点为1049kB的问题解释 文章目录 关于Linux下的parted分区工具显示起始点为1049kB的问题解释1 问题展示&#xff1a;2 原因3 修改为KiB方式显示4 最后 1 问题展示&#xff1a; kevinTM1701-b38cbc23:~$ sudo parted /dev/nvme1n1 GNU Part…

SAP 开发编辑界面-关闭助手

打开关闭助手时的开发界面如下&#xff1a; 关闭关闭助手后的界面如下&#xff1a; 菜单栏&#xff1a; 编辑--》修改操作--》关闭助手
最新文章