大纲
前言
概念介绍
安全架构
系统的安全架构有以下三大方面:
认证 (Authentication)
: 登录系统,用户系统(解决你是谁的问题)授权 (Authorization)
: 权限管理,用户授权(解决你能干什么的问题)攻击防护
- XSS (Cross-site scripting)
- CSRF (Cross-site request forgery)
- CORS (Cross-Origin Resource Sharing)
- SQL 注入
权限模型
ACL 模型
- ACL (Access Controll List)
- 用户(t_user)
- 用户_权限 (t_user_perm)
- 权限(t_permission)
RBAC 模型
- RBAC (Role Based Access Controll)
- 用户 (
t_user
) - 用户_角色 (
t_user_role
) - 角色 (
t_role
) - 角色_权限 (
t_role_perm
) - 权限 (
t_permission
)
Spring Security
工作原理
过滤器链架构
Spring Security 的底层利用 FilterChainProxy
封装了一系列过滤器链,并实现了各种安全过滤功能。
Servlet 三大组件
Servlet 的三大组件分别是:Servlet、Filter (过滤器)、Listener (监听器)。
FilterChainProxy
SecurityFilterChain
使用示例
核心内容
WebSecurityConfigurerAdapter
@EnableGlobalMethodSecurity
:开启全局方法安全配置@Secured
@PreAuthorize
@PostAuthorize
UserDetailService
:获取用户详细信息(用户基本信息、用户角色、用户权限)的 Service 类
方法安全
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @SpringBootApplication @EnableGlobalMethodSecurity(securedEnabled = true) public class SampleSecureApplication {
}
@Service public class MyService {
@Secured("ROLE_USER") public String secure() { return "Hello Security"; }
}
|
HTTP 安全
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @Configuration @Order(SecurityProperties.BASIC_AUTH_ORDER - 10) public class ApplicationConfigurerAdapter extends WebSecurityConfigurerAdapter {
@Override protected void configure(HttpSecurity http) throws Exception { http.antMatcher("/match1/**") .authorizeRequests() .antMatchers("/match1/user").hasRole("USER") .antMatchers("/match1/spam").hasRole("SPAM") .anyRequest().isAuthenticated(); }
}
|
整合案例
本章节完整的案例代码可以直接从 GitHub 下载对应章节 spring-boot3-16
。
准备工作
引入依赖项
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
<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.thymeleaf.extras</groupId> <artifactId>thymeleaf-extras-springsecurity6</artifactId> </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>
|
创建首页的页面
1 2 3 4 5 6 7 8 9 10 11
| <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Welcome Page</title> </head> <body> <h3>Welcome to here.</h3> <a th:href="@{/hello}">点击跳转 Hello 页面</a> </body> </html>
|
创建登录的页面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Login page</title> </head> <body> <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="登录" /></div> </form> </body> </html>
|
创建 Hello 页面
1 2 3 4 5 6 7 8 9 10
| <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Hello Page</title> </head> <body> <h3>Hello Spring Security.</h3> </body> </html>
|
核心代码
主启动类
提示
在主启动类上添加 @EnableMethodSecurity
注解,即开启方法级别的角色权限控制,这样就可以在方法上使用 @Secured
、@PreAuthorize
、@PostAuthorize
等注解了。
1 2 3 4 5 6 7 8 9
| @EnableMethodSecurity @SpringBootApplication public class MainApplication {
public static void main(String[] args) { SpringApplication.run(MainApplication.class, args); }
}
|
控制器类
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @Controller public class LoginController {
@GetMapping("/login") public String login() { return "/login"; }
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @Controller public class HelloController {
@GetMapping("/hello") @PreAuthorize("hasAuthority('file_read')") public String hello() { return "/hello"; }
}
|
安全配置类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| @Configuration public class WebSecurityConfiguration {
@Bean SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception { http.authorizeHttpRequests(registry -> { registry .requestMatchers(("/")).permitAll() .anyRequest().authenticated(); });
http.formLogin(formLoginConfigurer -> { formLoginConfigurer.loginPage("/login").permitAll(); });
http.logout(logoutConfigurer -> { logoutConfigurer.permitAll(); });
return http.build(); }
@Bean public UserDetailsService userDetailsService(PasswordEncoder passwordEncoder) { UserDetails user = User.withUsername("admin") .password(passwordEncoder.encode("123456")) .roles("admin", "hr") .authorities("file_read", "file_write") .build(); return new InMemoryUserDetailsManager(user); }
@Bean public PasswordEncoder passwordEncoder () { return new BCryptPasswordEncoder(); }
}
|
提示
除了可以使用上述的 UserDetailsService
类自定义用户信息(账号、密码、角色等),还可以直接在 YML / Properties 配置文件中指定,如下所示:
1 2 3
| spring.security.user.name=admin spring.security.user.password=123456 spring.security.user.roles=admin,hr
|
自动配置原理
- Spring Security 的自动配置类:
SecurityAutoConfiguration
、SpringBootWebSecurityConfiguration
、SecurityDataConfiguration
、SecurityFilterAutoConfiguration
… - Spring Security 的所有配置都在
SecurityProperties
,以 spring.security
为配置前缀 - 导入默认的
SecurityFilterChain
组件- 所有请求都需要认证(登录)
- 支持使用 HTTP Basic 方式登录
- 默认开启表单登录: Spring Security 提供一个默认登录页面,未经登录的所有请求都需要登录
@EnableWebSecurity
生效WebSecurityConfiguration
生效,Web 安全配置HttpSecurityConfiguration
生效,HTTP 安全配置@EnableGlobalAuthentication生效
:全局安全认证生效AuthenticationConfiguration
:认证配置