授权管理的实现在SpringSecurity中非常灵活,可以帮助应用程序实现以下两种常见的授权需求:

  • 用户-权限-资源 用户对应一些权限
  • 用户-角色-资源 用户对应角色,角色具有访问资源的权限
  • 用户-角色-权限-资源 RBAC 基于角色的访问控制,将用户权限分配和管理与角色相关联

1 基于request的授权

1.1 用户-权限-资源

需求

  • 具有USER_LIST权限用户可以访问/user/list
  • 具有USER_ADD权限用户可以访问/user/add

配置权限

1
2
3
4
5
6
7
8
9
10
11
12
13
@Configuration  
public class WebSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(
authorize->authorize
.requestMatchers("/user/list").hasAuthority("USER_LIST")
.requestMatchers("/user/add").hasAuthority("USER_ADD")
.anyRequest().authenticated()
);
......
}
}

采用硬编码的格式写入权限

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Component  
public class DBUserDetailsManager implements UserDetailsManager, UserDetailsPasswordService {
......
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
userQueryWrapper.eq("username", username);
User user = userMapper.selectOne(userQueryWrapper);
if (user == null){
throw new UsernameNotFoundException("用户不存在");
}else{
Collection<GrantedAuthority> authorities = new ArrayList<>();
authorities.add((GrantedAuthority) () -> "ROLE_USER");
authorities.add((GrantedAuthority) () -> "USER_LIST");
authorities.add((GrantedAuthority) () -> "USER_ADD");
return new org.springframework.security.core.userdetails.User(
user.getUsername(), user.getPassword(), user.isEnabled(),
true, true, true,
authorities);
}
}
......
}

错误处理
即没有权限的用户访问资源时,不能直接返回403

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class MyAccessDeniedHandler implements AccessDeniedHandler {  
@Override
public void handle(HttpServletRequest request,
HttpServletResponse response,
AccessDeniedException accessDeniedException)
throws IOException, ServletException {
HashMap<Object,Object> result = new HashMap<>();
result.put("code", -1);
result.put("msg", "权限不足,请联系管理员!");
String json = JSON.toJSONString(result);
response.setContentType("application/json;charset=utf-8");
response.getWriter().println(json);

}
}

配置类:

1
2
3
4
5
6
7
8
9
10
11
@Configuration  
public class WebSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.exceptionHandling(exception->exception
.authenticationEntryPoint(new MyAuthenticationEntryPoint())
.accessDeniedHandler(new MyAccessDeniedHandler())
);
....
}
}

![[Pasted image 20240902173112.png]]

1.2 用户-角色-资源

需求
角色为ADMIN的用户才能访问 /user/** 路径下的资源

角色配置

1
2
3
4
5
6
7
 http.authorizeHttpRequests(  
authorize->authorize
// .requestMatchers("/user/list").hasAuthority("USER_ADMIN")
// .requestMatchers("/user/add").hasAuthority("USER_ADD")
.requestMatchers("/user/**").hasRole("ADMIN")
.anyRequest().authenticated()
);

硬编码写入角色ADMIN

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
@Override  
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
userQueryWrapper.eq("username", username);
User user = userMapper.selectOne(userQueryWrapper);
if (user == null){
throw new UsernameNotFoundException("用户不存在");
}else{
// Collection<GrantedAuthority> authorities = new ArrayList<>();
// authorities.add((GrantedAuthority) () -> "ROLE_USER");
// authorities.add((GrantedAuthority) () -> "USER_LIST");
// authorities.add((GrantedAuthority) () -> "USER_ADD");
// return new org.springframework.security.core.userdetails.User(
// user.getUsername(), user.getPassword(), user.isEnabled(),
// true, true, true,
// authorities);
return org.springframework.security.core.userdetails.User
.withUsername(user.getUsername())
.password(user.getPassword())
.disabled(!user.isEnabled())
.credentialsExpired(false)
.accountLocked(false)
.roles("ADMIN")
.build();
}
}

1.3 用户-角色-权限-资源 (RBAC)

基于角色的访问控制是一种常用的数据库设计访问,他将用户的权限分配和管理与角色关联,以下是一个基本的RBAC数据库设计方案:

1 用户、角色、权限表

列名 数据类型 描述
user_id int 用户id
username varchar 用户名
password varchar 密码
列名 数据类型 描述
role_id int 角色ID
role_name varchar 角色名称
description varchar 角色描述
列名 数据类型 描述
permission_id int 权限ID
permission_name varchar 权限名称
description varchar 权限描述

2 用户角色关联表

列名 数据类型 描述
user_role_id int 用户角色关联id
user_id int 用户ID
role_id int 角色ID
3 角色权限关联表
列名 数据类型 描述
role_permission_id int 角色权限关联id
role_id int 角色ID
permission_id int 权限ID

2 基于方法的授权

2.1 开启方法授权

在配置文件中添加注解 @EnableMethodSecurity , 开启后若不添加约束允许访问所有资源

1
2
3
4
5
@Configuration  
@EnableMethodSecurity
public class WebSecurityConfig {
...
}

2.2 controller约束

在api上添加权限注解 @PreAuthorize

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@RestController  
public class IndexController {

@GetMapping("/")
@PreAuthorize("hasRole('ROLE_ADMIN')")
public HashMap<Object,Object> index(){
HashMap<Object, Object> result = new HashMap<>();
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
result.put("code",0);
result.put("authentication",authorities);
return result;
}
}