安全框架
● Apache Shiro
● Spring Security
● 自研:Filter
权限模型
1.RBAC(Role Based Access Controll)
- 用户(t_user)
- id,username,password,xxx
- 1,zhangsan
- 2,lisi
- 用户_角色(t_user_role)【N 对 N 关系需要中间表】
- zhangsan, admin
- zhangsan,common_user
- lisi, hr
- lisi, common_user
- 角色(t_role)
- id,role_name
- admin
- hr
- common_user
- 角色_权限(t_role_perm)
- admin, 文件r
- admin, 文件w
- admin, 文件执行
- admin, 订单query,create,xxx
- hr, 文件r
- 权限(t_permission)
- id,perm_id
- 文件 r,w,x
- 订单 query,create,xxx
2.ACL(Access Controll List)
- 用户(t_user)
- zhangsan
- lisi
- 用户_权限(t_user_perm)
- zhangsan,文件 r
- zhangsan,文件 x
- zhangsan,订单 query
- 权限(t_permission)
- id,perm_id
- 文件 r,w,x
- 订单 query,create,xxx
安全架构
1.认证:Authentication
who are you?
登录系统,用户系统
2.授权:Authorization
what are you allowed to do?
权限管理,用户授权
3.攻击防护
● XSS(Cross-site scripting)——跨站脚本攻击
● CSRF(Cross-site request forgery)——跨站请求伪造
● CORS(Cross-Origin Resource Sharing)——跨域资源共享攻击
● SQL 注入
● …
Spring Security 原理
1.过滤器链架构
Spring Security 利用 FilterChainProxy 封装一系列拦截器链,实现各种安全拦截功能
Servlet三大组件:Servlet、Filter、Listener
2.FilterChainProxy
3.SecurityFilterChain
实战
新建项目-boot3-13-security
新建模块
boot3-13-security
创建模块
项 | 值 |
---|---|
名称 | boot3-13-security |
位置 | D:\Study-Java\2023\SpringBoot3-Study |
语言 | Java |
构建系统 | Maven |
JDK | 版本:17 供应商:Eclipse Temurin(AdoptOpenJDK HotSpot)17.0.8 位置:C:\Users\Administrator.jdks\temurin-17.0.8 |
主 ID | com.atguigu |
工件 ID | boot3-13-security |
软件包名称 | com.atguigu.boot3.security |
- SpringBoot
3.2.0
- 依赖项目
Developer Tools
-- Lombok
Web
-- Spring Web
Template Engines
-- Thymeleaf
Security
-- Spring Security
资源目录
│ pom.xml
│
├─src
│ ├─main
│ │ ├─java
│ │ │ └─com
│ │ │ └─atguigu
│ │ │ └─boot3
│ │ │ └─security
│ │ │ │ Boot313SecurityApplication.java
│ │ │ │
│ │ │ ├─cofig
│ │ │ │ AppSecurityConfiguration.java
│ │ │ │
│ │ │ └─controller
│ │ │ HelloController.java
│ │ │ LoginController.java
│ │ │
│ │ └─resources
│ │ │ application.properties
│ │ │
│ │ ├─static
│ │ └─templates
│ │ index.html
│ │ login.html
1.引入依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity6</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
2.页面
首页-index.html
<h1>Welcome To Spring Security!</h1>
<a th:href="@{/hello}">hello</a><br />
<a th:href="@{/world}">world</a>
登录页-login.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org">
<head>
<title>Spring Security Example</title>
</head>
<body>
<div th:if="${param.error}">Invalid username and password.</div>
<div th:if="${param.logout}">You have been logged out.</div>
<form th:action="@{/login}" method="post">
<div>
<label> User Name : <input type="text" name="username" /> </label>
</div>
<div>
<label> Password: <input type="password" name="password" /> </label>
</div>
<div><input type="submit" value="Sign In" /></div>
</form>
</body>
</html>
3.控制器
Login
package com.atguigu.boot3.security.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class LoginController {
@GetMapping("/login")
public String loginPage() {
return "login";
}
}
Hello
package com.atguigu.boot3.security.controller;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "Hello Spring Security!";
}
@PreAuthorize("hasAuthority('world_exec')")
@GetMapping("/world")
public String world() {
return "Hello Spring Security!";
}
}
4.配置类
package com.atguigu.boot3.security.cofig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
/**
* 配置类
* 1. 自定义请求授权规则:http.authorizeHttpRequests
* 2. 自定义登录规则:http.formLogin
* 3. 自定义用户信息查询规则:UserDetailsService
* 4. 开启方法级别的精确权限控制:EnableMethodSecurity
*/
@Configuration
@EnableMethodSecurity
public class AppSecurityConfiguration {
/**
* 自定义请求授权规则
* @param http HttpSecurity
* @return 请求授权规则
* @throws Exception 异常信息
*/
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
//请求授权
http.authorizeHttpRequests(registry -> {
registry.requestMatchers("/").permitAll()//1. 首页无需登录
.anyRequest().authenticated();//2. 剩下的任意请求都需要认证(登录)
});
//表单登录
//3. 表单登录功能:开启默认表单登录功能,Spring Security 提供默认登录页
http.formLogin(formLogin -> {
//自定义登录页位置,并且所有人都能访问
formLogin.loginPage("/login").permitAll();
});
return http.build();
}
/**
* 自定义登录规则
* @param passwordEncoder 密码加密器
* @return 用户详情信息
*/
@Bean
UserDetailsService userDetailsService(PasswordEncoder passwordEncoder) {
//用户信息
UserDetails zhangsan = User.withUsername("zhangsan")
.password(passwordEncoder.encode("123456"))
.roles("admin", "hr")
.authorities("file_read", "file_write")
.build();
UserDetails lisi = User.withUsername("lishi")
.password(passwordEncoder.encode("123456"))
.roles("hr")
.authorities("file_read")
.build();
UserDetails wangwu = User.withUsername("wangwu")
.password(passwordEncoder.encode("123456"))
.roles("admin")
.authorities("file_write","world_exec")
.build();
//默认内存中保存所有用户信息
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager(zhangsan, lisi, wangwu);
return manager;
}
/**
* 密码加密器
* @return 密码加密器
*/
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
5.测试
无权限
Welcome To Spring Security!
hello
world
- 点击
world
,进入 http://localhost:8080/login
User Name :zhangsan
Password:123456
提示无权限
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Mon Jan 08 11:57:28 CST 2024
There was an unexpected error (type=Forbidden, status=403).
有权限
Welcome To Spring Security!
hello
world
- 点击
world
,进入 http://localhost:8080/login
User Name :wangwu
Password:123456
有权限
Hello Spring Security!