授权管理的实现在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/**").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{
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; } }
|