SpringSecurity:权限控制
1 数据准备
创建 sys_permission 表并插入数据
CREATE TABLE `sys_permission` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`url` varchar(255) DEFAULT NULL,
`role_id` int(11) DEFAULT NULL,
`permission` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `fk_roleId` (`role_id`),
CONSTRAINT `fk_roleId` FOREIGN KEY (`role_id`) REFERENCES `sys_role` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
2 创建 POJO、Mapper、Service
pojo
/**
* 权限实体类
*/
@Data
public class SysPermission implements Serializable {
static final long serialVersionUID = 1L;
private Integer id;
private String url;
private Integer roleId;
private String permission;
private List<String> permissions;
public List<String> getPermissions() {
return Arrays.asList(this.permission.trim().split(","));
}
public void setPermissions(List<String> permissions) {
this.permissions = permissions;
}
}
mapper
@Mapper
public interface SysPermissionMapper {
@Select("SELECT * FROM sys_permission WHERE role_id=#{roleId}")
List<SysPermission> listByRoleId(Integer roleId);
}
@Mapper
public interface SysRoleMapper {
@Select("SELECT * FROM sys_role WHERE id = #{id}")
SysRole selectById(Integer id);
@Select("SELECT * FROM sys_role WHERE name = #{name}")
SysRole selectByName(String name);
}
service
@Service
public class SysPermissionService {
@Autowired
private SysPermissionMapper permissionMapper;
/**
* 获取指定角色所有权限
*/
public List<SysPermission> listByRoleId(Integer roleId) {
return permissionMapper.listByRoleId(roleId);
}
}
@Service
public class SysRoleService {
@Autowired
private SysRoleMapper roleMapper;
public SysRole selectById(Integer id) {
return roleMapper.selectById(id);
}
public SysRole selectByName(String name) {
return roleMapper.selectByName(name);
}
}
3 自定义PermissionEvaluator
我们需要自定义对 hasPermission()
方法的处理,就需要自定义 PermissionEvaluator
,创建类 CustomPermissionEvaluator
,实现 PermissionEvaluator
接口。
package com.hl.hl01springsecurity.security.permissions;
import com.hl.hl01springsecurity.entity.SysPermission;
import com.hl.hl01springsecurity.service.SysPermissionService;
import com.hl.hl01springsecurity.service.SysRoleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Component;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
@Component
public class CustomPermissionEvaluator implements PermissionEvaluator {
@Autowired
private SysPermissionService permissionService;
@Autowired
private SysRoleService roleService;
@Override
public boolean hasPermission(Authentication authentication, Object targetUrl, Object targetPermission) {
// 获得loadUserByUsername()方法的结果
User user = (User)authentication.getPrincipal();
// 获得loadUserByUsername()中注入的角色
Collection<GrantedAuthority> authorities = user.getAuthorities();
// 遍历用户所有角色
for(GrantedAuthority authority : authorities) {
String roleName = authority.getAuthority();
Integer roleId = roleService.selectByName(roleName).getId();
// 得到角色所有的权限
List<SysPermission> permissionList = permissionService.listByRoleId(roleId);
// 遍历permissionList
for(SysPermission sysPermission : permissionList) {
// 获取权限集
List<String> permissions = sysPermission.getPermissions();
// 如果访问的Url和权限用户符合的话,返回true
if(targetUrl.equals(sysPermission.getUrl()) && permissions.contains(targetPermission)) {
return true;
}
}
}
return false;
}
@Override
public boolean hasPermission(Authentication authentication, Serializable serializable, String s, Object o) {
return false;
}
}
在 hasPermission()
方法中,参数 1 代表用户的权限身份,参数 2 参数 3 分别和 @PreAuthorize("hasPermission('/admin','r')")
中的参数对应,即访问 url 和权限。
思路如下:
- 通过
Authentication
取出登录用户的所有Role
- 遍历每一个
Role
,获取到每个Role
的所有Permission
- 遍历每一个
Permission
,只要有一个Permission
的url
和传入的url相同,且该Permission
中包含传入的权限,返回 true - 如果遍历都结束,还没有找到,返回false
在
WebSecurityConfig
中注册CustomPermissionEvaluator
/**
* 注入自定义PermissionEvaluator
*/
@Bean
public DefaultWebSecurityExpressionHandler webSecurityExpressionHandler(){
DefaultWebSecurityExpressionHandler handler = new DefaultWebSecurityExpressionHandler();
handler.setPermissionEvaluator(new CustomPermissionEvaluator());
return handler;
}
注意:
1、在WebSecurityConfig类中的注册bean webSecurityExpressionHandler时会报无法创建,不能覆盖,解决办法:在application.yml中加上spring.main.allow-bean-definition-overriding: true
2、类型转换问题,把CustomAuthenticationProvider类的authenticate返回类型换成return new UsernamePasswordAuthenticationToken(userDetails, inputPassword, userDetails.getAuthorities())