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();@Overridepublic 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;}@Overridepublic Collection<ConfigAttribute> getAllConfigAttributes() {return null;}@Overridepublic 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> {@Resourceprivate MySecurityMetadataSource mySecurityMetadataSource;@Overridepublic <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'")@GetMappingpublic 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.hqwc.cn/news/57202.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

开窗积累之学习更新版

1. 开窗使用1之 count range between current row and current row 将相同排序字段的值进行函数计算 selectsku_id,substr(create_date,1,7) date_month,order_id,create_date,sku_num*price,sum(sku_num*price) over (partition by sku_id order by substr(create_date,1,7)…

js-3:DOM常见的操作有哪些?

1、DOM 文档对象模型&#xff08;DOM&#xff09;是HTML和XML文档的编程接口。 它提供了对文档的结构化的表述&#xff0c;并定义了一种方式&#xff0c;可以使从程序中对该结构进行访问&#xff0c;从而改变文档的结构&#xff0c;样式跟内容。 任何HTML和XML文档都可以用DOM表…

R语言3_安装SeurateData

环境Ubuntu22/20, R4.1 在命令行中键入&#xff0c; apt-get update apt install libcurl4-openssl-dev libssl-dev libxml2-dev libcairo2-dev libgtk-3-dev # libcairo2-dev :: systemfonts # libgtk :: textshaping进入r语言交互环境&#xff0c;键入&#xff0c; instal…

RaabitMQ(三) - RabbitMQ队列类型、死信消息与死信队列、懒队列、集群模式、MQ常见消息问题

RabbitMQ队列类型 Classic经典队列 这是RabbitMQ最为经典的队列类型。在单机环境中&#xff0c;拥有比较高的消息可靠性。 经典队列可以选择是否持久化(Durability)以及是否自动删除(Auto delete)两个属性。 Durability有两个选项&#xff0c;Durable和Transient。 Durable表…

CS 144 Lab Seven -- putting it all together

CS 144 Lab Seven -- putting it all together 引言测试lab7.ccUDPSocketNetworkInterfaceAdapterTCPSocketLab7main方法子线程 小结 对应课程视频: 【计算机网络】 斯坦福大学CS144课程 Lab Six 对应的PDF: Checkpoint 6: putting it all together 引言 本实验无需进行任何编…

绘制曲线python

文章目录 import matplotlib.pyplot as plt# 提供的数据 x= [1,1.1,1.2,1.3,1.4,1.5,1.6,1.7,1.8,1.9,2,2.1,2.2,2.3,2.4,2.5,2.6,2.7,2.8,2.9,3,3.1,3.2,3.3,3.4,3.5,3.6,3.7,3.8,3.9,4,4.1,4.2,4.3,4.4,4.5,4.6,4.7,4.8,4.9,5,5.1,5.2,5.3,5.4,5.5,5.6,5.7,5.8,5.9,6,6.1,6.2…

【网络编程】揭开套接字的神秘面纱

文章目录 1 :peach:简单理解TCP/UDP协议 :peach:2 :peach:网络字节序 :peach:3 :peach:socket编程接口 :peach:3.1 :apple:socket 常见API :apple:3.2 :apple:sockaddr结构:apple: 4 :peach:简单的UDP网络程序 :peach:4.1 :apple:基本分析:apple:4.2 :apple:udpServer.hpp(重点…

Pytorch Tutorial【Chapter 2. Autograd】

Pytorch Tutorial 文章目录 Pytorch TutorialChapter 2. Autograd1. Review Matrix Calculus1.1 Definition向量对向量求导1.2 Definition标量对向量求导1.3 Definition标量对矩阵求导 2.关于autograd的说明3. grad的计算3.1 Manual手动计算3.2 backward()自动计算 Reference C…

Codeforces三道简单题

第一次使用Codeforces,.先刷三道简单题&#xff0c;最后附上怎么简单使用codeforces A. Watermelon 题目链接 : Problem - 4A - Codeforces 题面 : 思路 : 模拟 题解 : #include <stdio.h>int main(int argc, char const *argv[]) {int n;scanf("%d",&a…

Chatgpt AI newbing作画,文字生成图 BingImageCreator 二次开发,对接wxbot

开源项目 https://github.com/acheong08/BingImageCreator 获取cookie信息 cookieStore.get("_U").then(result > console.log(result.value)) pip3 install --upgrade BingImageCreator import os import BingImageCreatoros.environ["http_proxy"]…

26 MFC序列化函数

文章目录 Serialize对于存储文件的序列化 Serialize Serialize 是一个在 MFC (Microsoft Foundation Classes) 中常用的函数或概念。它用于将对象的数据进行序列化和反序列化&#xff0c;便于在不同的场景中保存、传输和恢复对象的状态。 在 MFC 中&#xff0c;Serialize 函数…

移动硬盘不显示盘符简单处理方法

通常情况下&#xff0c;将移动硬盘连接到电脑后会被赋予一个特定的盘符&#xff0c;以便用户可以访问和操作其中的文件和文件夹。然而&#xff0c;如果移动硬盘不显示盘符&#xff0c;意味着操作系统无法根据该硬盘的文件系统和存储信息识别出其所对应的盘符&#xff0c;这将导…