【Spring Security】 Spring Security 使用案例详细教程

news2024/11/8 9:48:43

文章目录

    • 一、Spring Security 入门案例
      • 1.1 导入依赖
      • 1.2 运行项目
      • 1.3 测试项目
    • 二、Spring Security 简单实现案例
      • 2.1 导入依赖
      • 2.2 配置 Spring Security
      • 2.3 创建访问资源
      • 2.4 测试身份验证和授权
    • 参考资料

一、Spring Security 入门案例

入门案例具体教程查看 Hello Spring Security :: Spring Security

1.1 导入依赖

根据 Getting Spring Security ,在 pom.xml 中导入 Spring Security 的相关依赖:

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

Spring Security 会在项目中启用 默认的身份验证和安全机制。无需额外的配置,就可以体验基本的用户认证。

1.2 运行项目

在不编写代码的情况下,Spring Boot 应用后,可以看到控制台输出日志:

Using generated security password: ed803299-ccd3-4ee0-8160-652eed542814

This generated password is for development use only. Your security configuration must be updated before running your application in production.

在没有配置 Authentication 的情况下,Spring Security 默认创建一个用户名为 user 的用户,并生成随机密码。该密码只用于开发环境,生产环境应自定义更安全的认证方式。

1.3 测试项目

测试 Basic HTTP Authentication 。

(1)未验证身份的请求

通过未验证身份直接访问受保护的路径时,Spring Security 会拒绝访问,并返回 401 Unauthorized 状态码:

$ curl -i http://localhost:8080/some/path
HTTP/1.1 401
Set-Cookie: JSESSIONID=598AEA648FB18B56CB28ACC1234AC174; Path=/; HttpOnly
WWW-Authenticate: Basic realm="Realm"
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Length: 0
Date: Thu, 07 Nov 2024 03:16:39 GMT

curl -i http://localhost:8080/admin/secure

curl -i -u user1:123456 http://localhost:8080/admin/secure

(2) 验证身份的请求

提供用户名 user 和生成的密码后,可以成功通过身份验证。若请求的资源不存在,Spring Boot 将返回 404 Not Found

$ curl -i -u user:ed803299-ccd3-4ee0-8160-652eed542814 http://localhost:8080/some/path
HTTP/1.1 404
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Type: application/json
Transfer-Encoding: chunked
Date: Thu, 07 Nov 2024 03:22:50 GMT

{"timestamp":"2024-11-07T03:22:50.775+00:00","status":404,"error":"Not Found","path":"/some/path"}

二、Spring Security 简单实现案例

本案例展示了如何使用 Spring Security 实现以下功能:

  1. 配置自定义用户名和密码。
  2. 基于角色的授权控制

2.1 导入依赖

根据 Getting Spring Security ,在 pom.xml 中导入 Spring Security 的相关依赖:

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

2.2 配置 Spring Security

根据 Java Configuration :: Spring Security,可以通过 Java 配置来自定义用户信息。同时,通过 Authorize HttpServletRequests 来定义不同角色的访问控制规则。

/**
 * Spring Security 配置类
 * <p>
 *     基于角色的权限控制使用案例
 * </p>
 *
 * @author zouhu
 * @data 2024-11-07 11:46
 */
@Configuration
@EnableWebSecurity
public class WebSecurityConfig{
    /**
     * 配置自定义用户,并给每个用户分配角色
     */
    @Bean
    protected UserDetailsManager userDetailsService() {
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();

        manager.createUser(User.withUsername("user")
                .password("{noop}123456")    // 使用 {noop} 前缀表示明文密码,仅用于开发和测试环境,生产环境推荐使用其他加密方式(如 BCrypt)。
                // .roles("USER")               // 分配 USER 角色,角色会自动添加前缀 ROLE_
                .authorities("USER")         // 使用 authorities 而不是 roles,角色不会添加前缀
                .build());

        manager.createUser(User.withUsername("admin")
                .password("{noop}admin123456")
                // .roles("ADMIN")    // 分配 ADMIN 角色,角色会自动添加前缀 ROLE_
                .authorities("ADMIN")
                .build());

        return manager;
    }

    /**
     * 配置角色的访问规则
     */
    @Bean
    public SecurityFilterChain web(HttpSecurity http) throws Exception {
        http
                .authorizeHttpRequests((authorize) -> {
                        // 管理员角色可访问的资源
                        authorize.requestMatchers("/admin/**").hasAuthority("ADMIN");

                        // 用户角色可访问的资源(注释掉的部分,如果未来需要启用可以取消注释)
                        authorize.requestMatchers("/user/**").hasAuthority("USER");

                        // 允许所有角色访问的资源
                        authorize.requestMatchers("/").permitAll();

                        // 其他所有请求都需要身份验证
                        authorize.anyRequest().authenticated();
                })
                .formLogin(withDefaults())  // 启用表单登录,默认登录页面为 /login
                .httpBasic(withDefaults()); // 启用 HTTP Basic Authentication

        return http.build();
    }
}

2.3 创建访问资源

@RestController
public class DemoController {
    @GetMapping("/user/secure")
    public String userAccess() {
        return "Hello User!";
    }

    @GetMapping("/admin/secure")
    public String adminAccess() {
        return "Hello Admin!";
    }

    @RequestMapping("/")
    public String home() {
        return "Welcome to the Home Page!";
    }
}

2.4 测试身份验证和授权

(1) 验证角色的权限

使用 @WithMockUser 注解来模拟不同角色的用户进行权限验证。

@SpringBootTest
@AutoConfigureMockMvc
class WebSecurityConfigTest {

    @Autowired
    private MockMvc mvc;

    /**
     *  测试未认证用户访问主页和受限资源
     */
    // @WithMockUser  // 未加 @WithMockUser 表示请求由未认证用户发出
    @Test
    void Unauthenticated() throws Exception {
        this.mvc.perform(get("/"))
                .andExpect(status().isOk())
                .andExpect(content().string("Welcome to the Home Page!")); // 预期返回 200 OK

        this.mvc.perform(get("/admin/secure"))
                .andExpect(status().isUnauthorized())  // 预期返回 401 Unauthorized
                .andExpect(header().string("WWW-Authenticate", "Basic realm=\"Realm\""));
    }


    /**
     * 测试默认用户(无特殊权限)的访问
     */
    @WithMockUser  // 模拟一个没有设置特定权限的默认用户
    @Test
    void NotAuthorityUser() throws Exception {
        this.mvc.perform(get("/"))
                .andExpect(status().isOk())
                .andExpect(content().string("Welcome to the Home Page!")); // 预期返回 200 OK

        this.mvc.perform(get("/user/secure"))
                .andExpect(status().isForbidden()); // 预期返回 403 Forbidden
    }

    /**
     *  测试具有 USER 权限的用户访问受限资源
     */
    @WithMockUser(authorities = "USER")
    @Test
    void UserAuthority() throws Exception {
        this.mvc.perform(get("/user/secure"))
                .andExpect(status().isOk())
                .andExpect(content().string("Hello User!"));  // 预期返回 200 OK

        this.mvc.perform(get("/admin/secure"))
                .andExpect(status().isForbidden());  // 预期返回  403 Forbidden
    }

    /**
     *  测试具有 ADMIN 权限的用户访问受限资源
     */
    @WithMockUser(authorities = "ADMIN")
    @Test
    void AdminAuthority() throws Exception {
        this.mvc.perform(get("/user/secure"))
                .andExpect(status().isForbidden()); // 预期返回 403 Forbidden

        this.mvc.perform(get("/admin/secure"))
                .andExpect(status().isOk())
                .andExpect(content().string("Hello Admin!"));  // 预期返回 200 OK
    }
}

(2)验证用户是否能访问

使用 curl 命令行工具模拟 HTTP 请求,验证不同用户权限。

# 未认证用户访问受限资源
$ curl -i  http://localhost:8080/admin/secure
HTTP/1.1 401
Set-Cookie: JSESSIONID=7C9FAE078D4DD87F777A6AA4836D12C8; Path=/; HttpOnly
WWW-Authenticate: Basic realm="Realm"
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Length: 0
Date: Thu, 07 Nov 2024 09:21:45 GMT

# 使用管理员账户访问受限资源
$  curl -i -u admin:admin123456 http://localhost:8080/admin/secure
HTTP/1.1 200
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Type: text/plain;charset=UTF-8
Content-Length: 12
Date: Thu, 07 Nov 2024 09:22:19 GMT

Hello Admin!

参考资料

Java Configuration :: Spring Security

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

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

相关文章

【开源免费】基于SpringBoot+Vue.JS医院管理系统(JAVA毕业设计)

博主说明&#xff1a;本文项目编号 T 062 &#xff0c;文末自助获取源码 \color{red}{T062&#xff0c;文末自助获取源码} T062&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析…

【循环引用及格式化输出】

垃圾回收机制 当一个值在内存中直接引用跟间接引用的量为0时&#xff0c;&#xff08;即这个值没有任何入口可以找到它&#xff09;那么这个值就会被清空回收♻️&#xff0c;释放内存空间&#xff1b; 列表在内存中的存储方式 1&#xff09;引用计数的两种方式 x "ea…

31.7K+ Star!AgentGPT:一个在浏览器中运行的Agent

AgentGPT 简介 AgentGPT[1] 是一个可以让你在浏览器中组装、配置和部署自主AI代理的项目。你可以为你的自定义AI命名,并让它去实现任何你想象中目标。它将尝试通过思考要执行的任务、执行它们并从结果中学习来达成目标。 项目特点 主要特点 自主AI代理:用户可以自定义AI并赋…

【大模型】通过Crew AI 公司的崛起之路学习 AI Agents 的用法

AI 技术的迅猛发展正以前所未有的速度重塑商业格局&#xff0c;而 AI Agents&#xff0c;作为新一代的智能自动化工具&#xff0c;正逐步成为创新型公司的核心力量。在本文中&#xff0c;我们将探讨如何利用 AI Agents 构建一家 AI 驱动的公司&#xff0c;并详细了解 Crew AI 创…

【Uniapp】Uniapp Android原生插件开发指北

前言 在uniapp开发中当HBuilderX中提供的能力无法满足App功能需求&#xff0c;需要通过使用Andorid/iOS原生开发实现时&#xff0c;或者是第三方公司提供的是Android的库&#xff0c;这时候可使用App离线SDK开发原生插件来扩展原生能力。 插件类型有两种&#xff0c;Module模…

网页版五子棋——用户模块(服务器开发)

前一篇文章&#xff1a;网页版五子棋—— WebSocket 协议-CSDN博客 目录 前言 一、编写数据库代码 1.数据库设计 2.配置 MyBatis 3.创建实体类 4.创建 UserMapper 二、前后端交互接口 1.登录接口 2.注册接口 3.获取用户信息 三、服务器开发 1.代码编写 2.测试后端…

Jenkins声明式Pipeline流水线语法示例

系列文章目录 docker搭建Jenkins2.346.3版本及常用工具集成配置(ldap、maven、ansible、npm等) docker安装低版本的jenkins-2.346.3,在线安装对应版本插件失败的解决方法 文章目录 系列文章目录jenkins流水线基础1、pipeline1.1、什么是pipeline&#xff1f;1.2、为什么使用pi…

【NLP】使用 SpaCy、ollama 创建用于命名实体识别的合成数据集

命名实体识别 (NER) 是自然语言处理 (NLP) 中的一项重要任务&#xff0c;用于自动识别和分类文本中的实体&#xff0c;例如人物、位置、组织等。尽管它很重要&#xff0c;但手动注释大型数据集以进行 NER 既耗时又费钱。受本文 ( https://huggingface.co/blog/synthetic-data-s…

【数据集】【YOLO】【目标检测】道路裂缝数据集 5466 张,YOLO/VOC格式标注!

数据集介绍 【数据集】道路裂缝数据集 5466 张&#xff0c;目标检测&#xff0c;包含YOLO/VOC格式标注。数据集中包含一种分类&#xff0c;检测范围城市道路裂缝、高速道路裂缝、乡村道路裂缝。 戳我头像获取数据&#xff0c;或者主页私聊博主哈~ 一、数据概述 道路裂缝检测…

C++用string实现字符串相加

. - 力扣&#xff08;LeetCode&#xff09; -》》》》》题目链接 实现思路&#xff1a;计算数字符串长度并用数组的方式计算出字符位置&#xff0c;用字符的ask码‘0’计算出字符本身。 class Solution { public:string addStrings(string num1, string num2) {string str;int…

easyexcel实现自定义的策略类, 最后追加错误提示列, 自适应列宽,自动合并重复单元格, 美化表头

easyexcel实现自定义的策略类, 最后追加错误提示列, 自适应列宽,自动合并重复单元格, 美化表头 原版表头和表体字体美化自动拼接错误提示列自适应宽度自动合并单元格使用Easyexcel使用poi导出 在后台管理开发的工作中,离不开的就是导出excel了. 如果是简单的导出, 直接easyexce…

brainpy 动力学编程基础

文章参考&#xff1a; 《神经计算建模实战——基于brainpy》 吴思 【brainpy学习笔记】基础知识2(动力学模型的编程基础)-CSDN博客 Brainpy手册 文章目录 积分器&#xff1a;定义ODE函数数值积分方法 更新函数和动力系统计算介绍什么是brainpy.DynamicalSystem&#xff1f;如…

高级图像处理工具

图像处理-高级 1、功能概览 随着社交媒体的普及和个人创作需求的增长&#xff0c;图像处理成为了日常生活中不可或缺的一部分。无论是专业的设计师还是爱好者&#xff0c;都需要一款强大的工具来帮助他们完成各种任务。今天&#xff0c;我们将介绍一款基于Python开发的高级图…

【Zookeeper集群搭建】安装zookeeper、zookeeper集群配置、zookeeper启动与关闭、zookeeper的shell命令操作

目录 一、安装Zookeeper 二、配置Zookeeper集群 三、Zookeeper服务的启动与关闭 四、Zookeeper的shell操作 前情提要&#xff1a;延续上篇【Hadoop和Hbase集群配置】继续配置Zookeeper&#xff0c;开启三台虚拟机Hadoop1、Hadoop2、Hadoop3&#xff0c;进入终端&#xff0c…

Transformer和BERT的区别

Transformer和BERT的区别比较表&#xff1a; 两者的位置编码&#xff1a; 为什么要对位置进行编码&#xff1f; Attention提取特征的时候&#xff0c;可以获取全局每个词对之间的关系&#xff0c;但是并没有显式保留时序信息&#xff0c;或者说位置信息。就算打乱序列中token…

Python爬虫如何处理验证码与登录

Python爬虫如何处理验证码与登录 Python 爬虫在抓取需要登录的网站数据时&#xff0c;通常会遇到两个主要问题&#xff1a;登录验证和验证码处理。这些机制是网站用来防止自动化程序过度抓取数据的主要手段。本文将详细讲解如何使用 Python 处理登录与验证码&#xff0c;以便进…

《深入浅出Apache Spark》系列②:Spark SQL原理精髓全解析

导读&#xff1a;SQL 诞生于 20 世纪 70 年代&#xff0c;至今已有半个世纪。SQL 语言具有语法简单&#xff0c;低学习门槛等特点&#xff0c;诞生之后迅速普及与流行开来。由于 SQL 具有易学易用的特点&#xff0c;使得开发人员容易掌握&#xff0c;企业若能在其计算机软件中支…

JS实现,防抖节流 + 闭包

防抖&#xff08;Debounce&#xff09; 防抖是指短时间内大量触发同一事件&#xff0c;只会在最后一次事件完成后延迟执行一次函数。 防抖的典型应用场景是输入框的搜索建议功能&#xff0c;用户输入时不需要每次输入都去查询&#xff0c;而是在用户停止输入一段时间后才进行…

安卓编程最方便的读写资料类SharedPreferences,多个APP共享

本文介绍Android平台进行数据存储的五大方式,分别如下: 1 使用SharedPreferences存储数据 2 文件存储数据 3 SQLite数据库存储数据 4 使用ContentProvider存储数据 5 网络存储数据 下面详细讲解这五种方式的特点 第一种&#xff1a; 使用SharedPreferences存储数据 …

数据分析:转录组差异fgsea富集分析

文章目录 介绍加载R包数据链接导入数据数据预处理DE testing: 2BP vs no-BP比较limma-voomLoad steroid dataIn No-BP patientsIn 2BP patientsCompare gene expression vs bacterial mass其他系统信息介绍 转录组差异fgsea富集分析是一种基于基因集的富集分析方法,它关注的是…