Spring Security + OAuth2
第一章 Spring Security 快速入门
第二章 Spring Security 自定义配置
第三章 Spring Security 前后端分离配置
第四章 Spring Security 身份认证
第五章 Spring Security 授权
第六章 OAuth2
文章目录
授权管理的实现在SpringSecurity中非常灵活,可以帮助应用程序实现以下两种常见的授权需求:
- 用户-权限-资源:例如张三的权限是添加用户、查看用户列表、李四的权限是查看用户列表
- 用户-角色-权限-资源:例如张三是角色是管理员、李四的角色是普通用户,管理员能做所有操作,普通用户只能查看信息
1、基于request的授权
1.1、用户-权限-资源
需求
- 具有USER_LIST权限的用户可以访问/user/list
- 具有USER_ADD权限的用户可以访问/user/add
配置权限
SecurityFilterChain
package com.security.demo.config;
import ...
@Configuration //配置类
public class WebSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
// authorizeHttpRequests() 开启授权保护
// anyRequest() 对所以请求开启授权保护
// authenticated()已认证请求会自动授权。
http.authorizeHttpRequests(
authorize -> authorize
//具有USER_LIST权限的用户可以访问/user/list
.requestMatchers("/user/list").hasAnyAuthority("USER_LIST")
//具有USER_ADD权限的用户可以访问/user/addd
.requestMatchers("/user/add").hasAnyAuthority("USER_ADD")
//对所有请求开启授权保护
.anyRequest()
//已认证的请求会被自动授权
.authenticated()
);
...
}
授权权限
DBUserDetailsManager中的loadUserByUsername方法:
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
QueryWrapper<User> queryWrapper = new QueryWrapper();
queryWrapper.eq("username",username);
User user = userMapper.selectOne(queryWrapper);
if (user==null){
throw new UsernameNotFoundException(username);
}else{
Collection<GrantedAuthority> authorities = new ArrayList<>();
//模拟权限
authorities.add(()->"USER_LIST");
authorities.add(()->"USER_ADD");
return new org.springframework.security.core.userdetails.User(
user.getUsername(),
user.getPassword(),
user.getEnabled(),
true,//用户账号是否过期。
true,//用户凭证是否过期
true,//未被锁定
authorities//权限列表
);
}
}
请求未授权的接口
实现AccessDeniedHandler 接口
package com.security.demo.config;
public class MyAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException exception) throws IOException, ServletException {
//创建结果对象
HashMap result = new HashMap();
result.put("code",-1);
result.put("message","没有权限");
//转换成json字符串
String json = JSON.toJSONString(result);
//返回响应
response.setContentType("application/json;charset=UTF-8");
response.getWriter().println(json);
}
}
SecurityFilterChain添加配置请求未授权的处理。
package com.security.demo.config;
import ...
@Configuration //配置类
public class WebSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
...
http.exceptionHandling(exception -> {
exception.accessDeniedHandler(new MyAccessDeniedHandler());//请求未授权的处理
});
...
}
1.2、用户-角色-资源
配置角色
package com.security.demo.config;
import ...
@Configuration //配置类
public class WebSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(
authorize -> authorize
.requestMatchers("/user/**").hasRole("ADMIN")
.anyRequest()
.authenticated()
);
...
}
授权角色
@Component
public class DBUserDetailsManager implements UserDetailsManager, UserDetailsPasswordService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
QueryWrapper<User> queryWrapper = new QueryWrapper();
queryWrapper.eq("username",username);
User user = userMapper.selectOne(queryWrapper);
if (user==null){
throw new UsernameNotFoundException(username);
}else{
//模拟授权
return org.springframework.security.core.userdetails.User
.withUsername(user.getUsername())
.password(user.getPassword())
.disabled(!user.getEnabled())//用户是否禁用
.credentialsExpired(false)//是否过期
.accountLocked(false)
.roles("ADMIN")
.build();
}
}
}
1.3、用户-角色-权限-资源
RBAC(Role-Based Access Control,基于角色的访问控制)是一种常用的数据设计方案,它将用户的权限分配和管理与角色相关联。以下是一个基本的RBAC数据库设计方案的示例:
1、用户表(User table):包含用户的基本信息,例如用户名、密码和其他身份验证信息。
列名 | 数据类型 | 描述 |
---|---|---|
user_id | int | 用户ID |
username | varchar | 用户名 |
password | varchar | 密码 |
varchar | 电子邮件 | |
… | … | … |
2、角色表(Role table):储存所有可能得角色及其描述。
列名 | 数据类型 | 描述 |
---|---|---|
role_id | int | 角色ID |
role_name | varchar | 角色名称 |
description | varchar | 角色描述 |
… | … | … |
3、权限表(Permission table):定义系统中所有可能得权限
列名 | 数据类型 | 描述 |
---|---|---|
permission_id | int | 权限ID |
permission_name | varchar | 权限名称 |
description | varchar | 角色描述 |
… | … | … |
4、用户角色关联表(User-Role table):将用户与角色关联起来。
列名 | 数据类型 | 描述 |
---|---|---|
user_role_id | int | 用户角色关联ID |
user_id | int | 用户ID |
role_id | int | 角色ID |
… | … | … |
5、角色权限关联表(Role-Permission table):将角色与权限关联起来。
列名 | 数据类型 | 描述 |
---|---|---|
role_permission_id | int | 用户角色关联ID |
role_id | int | 角色ID |
permission_id | int | 权限ID |
… | … | … |
在这个设计方案中,用户可以被分配一个或多个角色,而每个角色又可以具有一个或多个权限。通过对用户角色关联和角色权限关联表进行操作,可以实现灵活的权限管理和访问控制。
2、基于方法的授权
2.1、开启方法授权
在配置文件中添加@EnableMethodSecurity注解,并修改authorizeHttpRequests
@Configuration //配置类
@EnableMethodSecurity
public class WebSecurityConfig {
...
http.authorizeHttpRequests(
authorize -> authorize
.anyRequest()
.authenticated()
);
}
2.2、给用户授予角色和权限
DBUserDetailsManager中的loadUserByUsername方法:
return org.springframework.security.core.userdetails.User
.withUsername(user.getUsername())
.password(user.getPassword())
.disabled(!user.getEnabled())//用户是否禁用
.credentialsExpired(false)//是否过期
.accountLocked(false)
.roles("ADMIN")
//authorities和roles不能同时使用会覆盖
.authorities("USER_ADD","USER_LIST")
.build();
}
2.3、常用授权注解
@GetMapping(path = "/list")
@PreAuthorize("hasRole('ADMIN') and authentication.name == 'abc'")
public List<User> getList(){
return userService.list();
}
@PreAuthorize("hasAuthority('USER_ADD')")
@PostMapping(path = "/add")
public void add(@RequestBody User user){
userService.saveUserDetails(user);
}