[spring] rest api security

[spring] rest api security

之前的 rest api CRUD 都没有实现验证(authentication)和授权(Authorization),这里使用 Spring security 进行补全

spring security 是一个非常灵活、可延伸的实现方式,比较简单的可以通过注解(declarative)的方式实现,想要更具体的,也可以通过编程式(programmatic)实现。

整体流程大概如下:

在这里插入图片描述

POM 更新

		<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency>

一旦添加了 dependency、rebuild 之后,spring boot 就会默认开启验证功能,默认情况下提供的密码:

在这里插入图片描述

效果如下:

在这里插入图片描述

在这里插入图片描述

修改默认密码的方式是修改 properties 文件:

# Spring Security Property
spring.security.user.name=admin
spring.security.user.password=1234

效果如下:

在这里插入图片描述

基础实现

用户验证

下面是一个基础的用户权限管理:

User IDPasswordRoles
workerpass1234employee
bosspwdSecureemployee, manager
admin789passwordemployee, manager, admin

这里可以通过手写的方式写入用户名和权限,完成基础设定:

@Configuration
public class DemoSecurityConfig {@Beanpublic InMemoryUserDetailsManager userDetailsManager() {UserDetails worker = User.builder().username("worker").password("{noop}pass1234").roles("employee").build();UserDetails boss = User.builder().username("boss").password("{noop}pass1234").roles("employee", "manager").build();UserDetails admin = User.builder().username("admin").password("{noop}pass1234").roles("employee", "manager", "admin").build();return new InMemoryUserDetailsManager(worker, boss, admin);}
}

这个情况下 spring 会选择代码中写入的用户名和密码,而不是 properties 文件中,效果如下:

在这里插入图片描述

权限设定

权限的部分则是通过对 role 的授权实现,例如说 employee 只有读的权利,manager 有写的权利,admin 有删的权限:

HTTP MethodEndpointCRUD ActionRole
GET/api/employeesRead Allemployee
GET/api/employees/{id}Read Singleemployee
POST/api/employeesCreatemanager
PUT/api/employees/{id}Updatemanager
DELETE/api/employees/{id}Deleteadmin

这个部分可以通过添加 requestMatchers 实现,如:

@Beanpublic SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {httpSecurity.authorizeHttpRequests(configurer ->configurer.requestMatchers(HttpMethod.GET, "/api/employees").hasRole("employee").requestMatchers(HttpMethod.GET, "/api/employees/**").hasRole("employee").requestMatchers(HttpMethod.POST, "/api/employees").hasRole("manager").requestMatchers(HttpMethod.PATCH, "/api/employees").hasRole("manager").requestMatchers(HttpMethod.PUT, "/api/employees").hasRole("manager").requestMatchers(HttpMethod.PUT, "/api/employees/**").hasRole("manager").requestMatchers(HttpMethod.DELETE, "/api/employees/**").hasRole("admin"));// use http basic authhttpSecurity.httpBasic(Customizer.withDefaults());// disable CSRF// in general, not required for stateless REST APIshttpSecurity.csrf(AbstractHttpConfigurer::disable);return httpSecurity.build();}

效果如下:

roleCRUD结果
employeedelete在这里插入图片描述
employeecreate在这里插入图片描述
employeeget在这里插入图片描述
bosscreate在这里插入图片描述
bossdelete在这里插入图片描述
admincreate在这里插入图片描述
admindelete在这里插入图片描述

使用 JDBC 链接

这里使用数据库代替硬代码去实现

明文密码

这个 demo 使用明文密码进行实现,这样比较直观

sql 配置
USE `employee_directory`;DROP TABLE IF EXISTS `authorities`;DROP TABLE IF EXISTS `users`;---- Table structure for table `users`--CREATE TABLE `users` (`username` varchar(50) NOT NULL,`password` varchar(50) NOT NULL,`enabled` tinyint NOT NULL,PRIMARY KEY (`username`)) ENGINE=InnoDB DEFAULT CHARSET=latin1;---- Inserting data for table `users`--INSERT INTO `users`VALUES('john','{noop}test123',1),('mary','{noop}test123',1),('susan','{noop}test123',1);---- Table structure for table `authorities`--CREATE TABLE `authorities` (`username` varchar(50) NOT NULL,`authority` varchar(50) NOT NULL,UNIQUE KEY `authorities_idx_1` (`username`,`authority`),CONSTRAINT `authorities_ibfk_1` FOREIGN KEY (`username`) REFERENCES `users` (`username`)) ENGINE=InnoDB DEFAULT CHARSET=latin1;---- Inserting data for table `authorities`--INSERT INTO `authorities`VALUES('john','ROLE_EMPLOYEE'),('mary','ROLE_EMPLOYEE'),('mary','ROLE_MANAGER'),('susan','ROLE_EMPLOYEE'),('susan','ROLE_MANAGER'),('susan','ROLE_ADMIN');

这里的表名是 spring security 默认的名称,后面会说怎么配置,从而可以不用默认的表名。另外就是 {noop}test123,这个语法表示 no-op,即不对用户名加密。结果如下:

mysql> show tables from employee_directory;
+------------------------------+
| Tables_in_employee_directory |
+------------------------------+
| authorities                  |
| employee                     |
| users                        |
+------------------------------+
3 rows in set (0.00 sec)mysql> select * from employee_directory.authorities;
+----------+---------------+
| username | authority     |
+----------+---------------+
| john     | ROLE_EMPLOYEE |
| mary     | ROLE_EMPLOYEE |
| mary     | ROLE_MANAGER  |
| susan    | ROLE_ADMIN    |
| susan    | ROLE_EMPLOYEE |
| susan    | ROLE_MANAGER  |
+----------+---------------+
6 rows in set (0.00 sec)mysql> select * from employee_directory.users;;
+----------+---------------+---------+
| username | password      | enabled |
+----------+---------------+---------+
| john     | {noop}test123 |       1 |
| mary     | {noop}test123 |       1 |
| susan    | {noop}test123 |       1 |
+----------+---------------+---------+
3 rows in set (0.00 sec)

后面会有 dbeaver 而不是命令行显示数据,这里是 dbeaver 生成的 ER Diagram:

在这里插入图片描述

修改 POM 和配置文件
	<dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><scope>runtime</scope></dependency>

这个是添加对 mysql 的支持,下面是 properties 文件的修改:

# JDBC properties
spring.datasource.url=jdbc:mysql://localhost:3306/employee_directory
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.database-platform=org.hibernate.dialect.MySQLDialect
修改 java 代码

这个只需要修改 userDetailsManager 里的 dataSource 即可,这部分 srping 也会自动进行依赖注入:

    // add support for JDBC@Beanpublic UserDetailsManager userDetailsManager(DataSource dataSource) {return new JdbcUserDetailsManager((dataSource));}

最终效果如下:

在这里插入图片描述

⚠️:employee, admin, manager 在数据库里是大写的,之前实现是小写,所以需要修改

bcrypt 加密

bcrypt 是一个单方向的加密方式,无法通过已经 hash 的值去解密,这也是 spring security 支持的密码加密方式。

这里网上随便找了一个 bcrypt 加密的网站显示一下 string 对比的结果:

在这里插入图片描述

⚠️:就算是同一个 string,每次加密后获得的 hash 值都不会完全一致

sql 配置
USE `employee_directory`;DROP TABLE IF EXISTS `authorities`;
DROP TABLE IF EXISTS `users`;--
-- Table structure for table `users`
--CREATE TABLE `users` (`username` varchar(50) NOT NULL,`password` char(68) NOT NULL,`enabled` tinyint NOT NULL,PRIMARY KEY (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;--
-- Inserting data for table `users`
--
-- NOTE: The passwords are encrypted using BCrypt
--INSERT INTO `users`
VALUES
('john','{bcrypt}$2y$08$I9qqnyR8fMLO/WFQWLjzfe7TCz6357dM/CaXgppCReDdSMktqUIPW',1),
('mary','{bcrypt}$2y$08$I9qqnyR8fMLO/WFQWLjzfe7TCz6357dM/CaXgppCReDdSMktqUIPW',1),
('susan','{bcrypt}$2y$08$I9qqnyR8fMLO/WFQWLjzfe7TCz6357dM/CaXgppCReDdSMktqUIPW',1);--
-- Table structure for table `authorities`
--CREATE TABLE `authorities` (`username` varchar(50) NOT NULL,`authority` varchar(50) NOT NULL,UNIQUE KEY `authorities4_idx_1` (`username`,`authority`),CONSTRAINT `authorities4_ibfk_1` FOREIGN KEY (`username`) REFERENCES `users` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;--
-- Inserting data for table `authorities`
--INSERT INTO `authorities`
VALUES
('john','ROLE_EMPLOYEE'),
('mary','ROLE_EMPLOYEE'),
('mary','ROLE_MANAGER'),
('susan','ROLE_EMPLOYEE'),
('susan','ROLE_MANAGER'),
('susan','ROLE_ADMIN');

查看数据库,确定密码已经从明文更新为 bcrypt:

在这里插入图片描述

⚠️:bcrypt 的密码是 test1234

这个时候运行一下 postman,原本的 123 验证会失败,但是 1234 会通过:

在这里插入图片描述

自定义表名

sql 配置
USE `employee_directory`;DROP TABLE IF EXISTS `roles`;
DROP TABLE IF EXISTS `members`;--
-- Table structure for table `members`
--CREATE TABLE `members` (`user_id` varchar(50) NOT NULL,`pw` char(68) NOT NULL,`active` tinyint NOT NULL,PRIMARY KEY (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;--
-- Inserting data for table `members`
--
-- NOTE: The passwords are encrypted using BCrypt
--INSERT INTO `members`
VALUES
('john','{bcrypt}$2a$10$qeS0HEh7urweMojsnwNAR.vcXJeXR1UcMRZ2WcGQl9YeuspUdgF.q',1),
('mary','{bcrypt}$2a$10$qeS0HEh7urweMojsnwNAR.vcXJeXR1UcMRZ2WcGQl9YeuspUdgF.q',1),
('susan','{bcrypt}$2a$10$qeS0HEh7urweMojsnwNAR.vcXJeXR1UcMRZ2WcGQl9YeuspUdgF.q',1);--
-- Table structure for table `authorities`
--CREATE TABLE `roles` (`user_id` varchar(50) NOT NULL,`role` varchar(50) NOT NULL,UNIQUE KEY `authorities5_idx_1` (`user_id`,`role`),CONSTRAINT `authorities5_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `members` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;--
-- Inserting data for table `roles`
--INSERT INTO `roles`
VALUES
('john','ROLE_EMPLOYEE'),
('mary','ROLE_EMPLOYEE'),
('mary','ROLE_MANAGER'),
('susan','ROLE_EMPLOYEE'),
('susan','ROLE_MANAGER'),
('susan','ROLE_ADMIN');

这里会创建两个新的表去建立关联:

在这里插入图片描述

其中 role 等同于 auth,members 等同于 user

⚠️:这里新修改的密码是 fun123

java 更新

这里更新的地方要让 jdbcUserDetailsManager 能够找到用户和权限的表,就需要新写一下 query,让 spring security 通过新的 query 去找到 user 和 role:

    @Beanpublic UserDetailsManager userDetailsManager(DataSource dataSource) {JdbcUserDetailsManager jdbcUserDetailsManager = new JdbcUserDetailsManager((dataSource));// define query to retrieve a user by usernamejdbcUserDetailsManager.setUsersByUsernameQuery("select user_id, pw, active from members where user_id=?");// define query to retrieve the roles by usernamejdbcUserDetailsManager.setAuthoritiesByUsernameQuery("select user_id, role from roles where user_id=?");return jdbcUserDetailsManager;}

效果如下:

在这里插入图片描述

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

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

相关文章

C语言 | Leetcode C语言题解之第19题删除链表的倒数第N个结点

题目&#xff1a; 题解&#xff1a; struct ListNode* removeNthFromEnd(struct ListNode* head, int n) {struct ListNode* dummy malloc(sizeof(struct ListNode));dummy->val 0, dummy->next head;struct ListNode* first head;struct ListNode* second dummy;f…

安装 Kali NetHunter (完整版、精简版、非root版)、实战指南、ARM设备武器化指南、andrax、安卓渗透drozer

From&#xff1a;https://www.kali.org/docs/nethunter/ NetHunter 实战指南&#xff1a;https://www.vuln.cn/6430 乌云 存档&#xff1a;https://www.vuln.cn/wooyundrops 1、Kali NetHunter Kali NetHunter 简介 Net&#xff08;网络&#xff09;&#xff0c;hunter&#x…

uniapp开发h5端使用video播放mp4格式视频黑屏,但有音频播放解决方案

mp4格式视频有一些谷歌播放视频黑屏&#xff0c;搜狗浏览器可以正常播放 可能和视频的编码格式有关&#xff0c;谷歌只支持h.264编码格式的视频播放 将mp4编码格式修改为h.264即可 转换方法&#xff1a; 如果是自己手动上传文件可以手动转换 如果是后端接口调取的地址就需…

【亲测】国内如何支付Overleaf?Overleaf如何升级标准版专业版?Overleaf升级保姆级教程

0. 【必看】开通步骤简述 升级Overleaf的步骤简要总结如下&#xff1a; 使用虚拟信用卡平台WildCard开通虚拟信用卡&#xff08;从链接进入可以优惠15元人民币哦&#xff09;。开卡后&#xff0c;进入WIldcard找到卡片信息进入Overleaf绑定卡片并支付&#xff0c;完成支付后就…

南京观海微电子----快速判断出三极管的好坏

三极管其作用是把微弱信号放大成幅度值较大的信号。可分为硅NPN和锗PNP两种三极管。它有三个极&#xff0c;即基极B&#xff0c;集电极C&#xff0c;发射极E。 我们判断测量三极管时有一个最简易的方法&#xff0c;就是把所有三极管看成两个二极管组成。 可以把NPN管看着两个…

Typora导入功能使用详细

一、 pandoc安装&#xff08;导入需要的插件&#xff09; 1. 首次安装完typora&#xff0c;是没法导入的&#xff0c;需要安装pandoc&#xff0c;首先我们先在文件夹里面新建一个Typora文件&#xff0c;然后再找到导入功能点击就可以弹出安装的地址了 2. 点击文件可以找到导入…

毅速:3D打印技术助推压铸模效率飞跃

压铸模&#xff0c;作为压铸件成型的核心工具&#xff0c;其重要性不言而喻。如今&#xff0c;随着3D打印技术的崛起&#xff0c;压铸模的制造迎来了前所未有的革新&#xff0c;特别是在随形水路设计方面的应用&#xff0c;更是让制造效率实现了质的飞跃。 在传统压铸模制造中&…

springboot3整合consul实现服务注册和配置管理快速入门

服务注册&#xff1a; 配置管理&#xff1a; 注册中心的比较&#xff1a; 在微服务的世界中&#xff0c;服务注册是必不可少的。现在比较流行的也就是Consul和Nacos&#xff0c;Zookeeper没有管理界面&#xff0c;一般不建议使用&#xff0c;而Eureka已经处于停更&#xff0…

论文复现 MSE 均方误差 MAR 平均绝对值误差

1、均方误差&#xff08;L2损失&#xff09; 均方误差(MSE)是最常用的回归损失函数&#xff0c;计算方法是求预测值与真实值之间距离的平方和&#xff0c;公式如下&#xff1a; 2、平均绝对值误差&#xff08;L1损失&#xff09; 平均绝对误差&#xff08;MAE&#xff09;是另…

Python学习笔记13 - 元组

什么是元组 元组的创建方式 为什么要将元组设计为不可变序列&#xff1f; 元组的遍历

【leetcode面试经典150题】49. 合并区间(C++)

【leetcode面试经典150题】专栏系列将为准备暑期实习生以及秋招的同学们提高在面试时的经典面试算法题的思路和想法。本专栏将以一题多解和精简算法思路为主&#xff0c;题解使用C语言。&#xff08;若有使用其他语言的同学也可了解题解思路&#xff0c;本质上语法内容一致&…

2023年蓝桥杯——日期统计

目录 题目链接&#xff1a;1.日期统计 - 蓝桥云课 (lanqiao.cn) 题目描述 思路 代码思路 定义数据结构&#xff1a; 处理每一个月&#xff1a; 检查日期序列在num100中是否存在&#xff1a; 计数匹配的日期数&#xff1a; 输出结果&#xff1a; 代码实现 总结 题目链…

【JS】数组交换位置

公式 arr.splice(oldIndex, delCount, ...arr.splice(newIndex, delCount, arr[oldIndex])) arr - 操作的数组delCount - 删除的数组个数oldIndex - 交换位置的数组下标1newIndex - 交换位置的数组下标2...arr - 提取数组里的元素 splice删除元素时&#xff0c;返回一个数组&a…

如何在Linux部署MeterSphere并实现公网访问进行远程测试工作

文章目录 前言1. 安装MeterSphere2. 本地访问MeterSphere3. 安装 cpolar内网穿透软件4. 配置MeterSphere公网访问地址5. 公网远程访问MeterSphere6. 固定MeterSphere公网地址 前言 MeterSphere 是一站式开源持续测试平台, 涵盖测试跟踪、接口测试、UI 测试和性能测试等功能&am…

L1 【哈工大_操作系统】什么是操作系统

从本期开始&#xff0c;笔者将出一系列哈工大的《操作系统》课堂要点笔记&#xff0c;该课程应该算得上是国内最好的操作系统课程之一&#xff0c;也是哈工大CS课程含金量最高的课程之一。尤其是对于想学习国外课程《MIT 6.S081》《MIT 6.828》又基础不足的同学&#xff0c; 特…

Mathorcup 甲骨文识别

本资源主要包含第2-4问&#xff0c;第一问直接使用传统图像处理即可&#xff0c;需要有很多步骤&#xff0c;这一步大家自己写就行。 2 第2问&#xff0c;甲骨文识别 2.1 先处理源文件 原文件有jpg和json文件&#xff0c;都在一个文件夹下&#xff0c;需要对json文件进行处理…

[SystemVerilog]常见设计模式/实践

常见设计模式/实践 RTL 设计&#xff08;尤其是 ASIC&#xff09;的最终目标是制作出最小、最快的电路。为此&#xff0c;我们需要了解综合工具如何分析和优化设计。此外&#xff0c;我们还关注仿真速度&#xff0c;因为等待测试运行实际上是在浪费工程精力。虽然综合和仿真工…

基于STC12C5A60S2系列1T 8051单片机的带字库液晶显示器LCD12864数据传输并行模式显示图像应用

基于STC12C5A60S2系列1T 8051单片机的液晶显示器LCD12864显示图像应用 STC12C5A60S2系列1T 8051单片机管脚图STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式及配置STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式介绍液晶显示器LCD12864简单介绍一、LCD12864点阵型液…

2024最方便申请SSL证书方法介绍

申请SSL证书其实就像你去官方机构办个身份证&#xff0c;证明你的网站是合法且安全的。这里给你白话一点的简单步骤&#xff1a; 步骤一&#xff1a;确定需求 1. 域名&#xff1a;确保你有一个要申请证书的域名&#xff0c;就是你的网站地址&#xff0c;比如 www.example.com。…

MySQL Innodb中 可重复读隔离级别是否能完全规避幻读

一、MySQL 可重复读隔离级别下的幻读 在 MySQL Innodb引擎可重复读隔离级别下&#xff0c;已经尽可能最大程度的规避幻读的问题了&#xff0c;使得大多数情况下&#xff0c;重复读都是可以得到一致的结果。 针对于读数据&#xff0c;可以大致分为两种模式&#xff0c;快照读&…