2025-08-04-Mon-T-权限管理

1. Spring Security快速入门

Filter是由Servlet容器加上FilterChain进行管理的,然后SpringSecurity是通过在FilterChain中注册一个Filter的代理对象,然后,再到Spring容器中定义SpringSecurity的FilterChain, 这些spring容器中的FilterChain是通过再Servlet中定义的Filter代理对象进行管理的。

1.1 DefaultSecurityFilterChain

SpringSecurity默认的SecurityFilterChain

1.2 SecurityProperties

定义默认配置

2. Spring Security自定义配置

2.1 创建自定义配置

UserDetailsService 用来管理用户信息, InMemoryUserDetailManagerUserDetailsService的一个实现,用来管理内存的用户信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Configuration // 配置类
//@EnableWebSecurity // 开启Spring Security 的自定义配置(Spring Boot项目中,此注解可以省略
public class SecurityConfig {

@Bean
public UserDetailsService userDetailsService() {

//创建基于内存的用户信息管理器
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
//创建UserDetails对象,用于管理用户名、用户密码、用户角色、用户权限的内容
manager.createUser(User.withDefaultPasswordEncoder().username("user").password("password").roles("USER").build());
return manager;
}

}

基于内存的用户认证流程

  • 程序启动时
    • 创建InMemoryUserDetailsManager对象
    • 创建User对象,封装用户名和密码
    • 使用InMemoryUserDetailsManager将User对象存入内存
  • 校验用户时
    • SpringSecurity自动使用InMemoryUserDetailsManagerloadUserByUserName方法从内存中获取User对象
    • UsernamePasswordAuthenticationFilter过滤器中的attemptAuthentication方法中将用户输入的用户密码和从内存中获取到的用户信息进行比较,进行用户认证

2.2 基于数据库数据源的用户认证

  • 程序启动时
    • 创建DBUserDetailsManager对象, 实现 UserDetailsManager, UserDetailsPasswordService
  • 校验用户时
    • SpringSecurity自动使用DBUserDetailsManagerloadUserByUserName方法从数据库中获取User对象
    • 在UsernamePasswordAuthenticationFilter过滤器中的attemptAuthentication方法中将用户输入的用户密码和从数据库中获取到的用户信息进行比较,进行用户认证
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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75

@Component
public class DBUserDetailsManager implements UserDetailsManager, UserDetailsPasswordService {

@Resource
private UserDao userDao;

@Override
public UserDetails updatePassword(UserDetails user, String newPassword) {
return null;
}

/**
* 插入用户
* @param user
*/
@Override
public void createUser(UserDetails user) {
User newUser = new User();
newUser.setUsername(user.getUsername());
newUser.setPassword(user.getPassword());
newUser.setEnabled(true);

userDao.insert(newUser);


}

@Override
public void updateUser(UserDetails user) {

}

@Override
public void deleteUser(String username) {

}

@Override
public void changePassword(String oldPassword, String newPassword) {

}

@Override
public boolean userExists(String username) {
return false;
}

/**
*
* @param username
* @return
* @throws UsernameNotFoundException
*/
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
userQueryWrapper.eq("username",username);
User user = userDao.selectOne(userQueryWrapper);
if(user == null) {
throw new UsernameNotFoundException(username);
}else {
Collection<GrantedAuthority> grantedAuthorities = new ArrayList<>();
return new org.springframework.security.core.userdetails.User(
user.getUsername(),
user.getPassword(),
user.getEnabled(),
true,
true,
true,
grantedAuthorities);
}
}
}

3. 前后端分离

3.2 跨域问题解决

需要对开启一些接口的跨域访问

通过实现 WebMvcConfigurer接口统一配置,避免在每个Controller重复注解

1
2
3
4
5
6
7
8
9
10
11
12
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**") // 指定接口路径
.allowedOrigins("https://prod.example.com") // 仅允许此域名跨域,生产环境禁用通配符*
.allowedMethods("GET", "POST", "PUT") // 按需开放方法
.allowedHeaders("Content-Type", "Authorization")
.allowCredentials(true) // 允许携带Cookie
.maxAge(3600); // 预检请求缓存时间
}
}

4. 身份认证

5. 授权

6. OAuth2