# Spring Security动态权限管理
* Spring Security核心配置入口
~~~
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
...
@Autowired
private MyFilterSecurityInterceptor myFilterSecurityInterceptor;
@Override
protected void configure(HttpSecurity http) throws Exception {
...
registry.and()
...
//添加自定义权限过滤器
.addFilterBefore(myFilterSecurityInterceptor, FilterSecurityInterceptor.class)
}
}
~~~
* 权限管理过滤器 监控用户行为
~~~
@Component
public class MyFilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter {
@Autowired
private FilterInvocationSecurityMetadataSource securityMetadataSource;
@Autowired
public void setMyAccessDecisionManager(MyAccessDecisionManager myAccessDecisionManager) {
super.setAccessDecisionManager(myAccessDecisionManager);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
FilterInvocation fi = new FilterInvocation(request, response, chain);
invoke(fi);
}
public void invoke(FilterInvocation fi) throws IOException, ServletException {
InterceptorStatusToken token = super.beforeInvocation(fi);
try {
fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
} finally {
super.afterInvocation(token, null);
}
}
@Override
public void destroy() {
}
@Override
public Class<?> getSecureObjectClass() {
return FilterInvocation.class;
}
@Override
public SecurityMetadataSource obtainSecurityMetadataSource() {
return this.securityMetadataSource;
}
}
~~~
* 权限管理决断器 判断用户拥有的权限或角色是否有资源访问权限
~~~
@Component
public class MyAccessDecisionManager implements AccessDecisionManager {
@Override
public void decide(Authentication authentication, Object o, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
if(configAttributes==null){
return;
}
Iterator<ConfigAttribute> iterator = configAttributes.iterator();
while (iterator.hasNext()){
ConfigAttribute c = iterator.next();
String needPerm = c.getAttribute();
for(GrantedAuthority ga : authentication.getAuthorities()) {
// 匹配用户拥有的ga 和 系统中的needPerm
if(needPerm.trim().equals(ga.getAuthority())) {
return;
}
}
}
throw new AccessDeniedException("抱歉,您没有访问权限");
}
@Override
public boolean supports(ConfigAttribute configAttribute) {
return true;
}
@Override
public boolean supports(Class<?> aClass) {
return true;
}
}
~~~
* 权限资源管理器 为权限决断器提供支持
~~~
@Component
public class MySecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
@Autowired
private PermissionService permissionService;
private Map<String, Collection<ConfigAttribute>> map = null;
/**
* 加载权限表中所有操作请求权限
*/
public void loadResourceDefine(){
map = new HashMap<>(16);
Collection<ConfigAttribute> configAttributes;
ConfigAttribute cfg;
// 获取启用的权限操作请求
List<Permission> permissions = permissionService.findByTypeAndStatusOrderBySortOrder(CommonConstant.PERMISSION_OPERATION, CommonConstant.STATUS_NORMAL);
for(Permission permission : permissions) {
if(StrUtil.isNotBlank(permission.getTitle())&&StrUtil.isNotBlank(permission.getPath())){
configAttributes = new ArrayList<>();
cfg = new SecurityConfig(permission.getTitle());
//作为MyAccessDecisionManager类的decide的第三个参数
configAttributes.add(cfg);
//用权限的path作为map的key,用ConfigAttribute的集合作为value
map.put(permission.getPath(), configAttributes);
}
}
}
/**
* 判定用户请求的url是否在权限表中
* 如果在权限表中,则返回给decide方法,用来判定用户是否有此权限
* 如果不在权限表中则放行
* @param o
* @return
* @throws IllegalArgumentException
*/
@Override
public Collection<ConfigAttribute> getAttributes(Object o) throws IllegalArgumentException {
if(map == null){
loadResourceDefine();
}
//Object中包含用户请求request
String url = ((FilterInvocation) o).getRequestUrl();
PathMatcher pathMatcher = new AntPathMatcher();
Iterator<String> iterator = map.keySet().iterator();
while (iterator.hasNext()) {
String resURL = iterator.next();
if (StrUtil.isNotBlank(resURL)&&pathMatcher.match(resURL,url)) {
return map.get(resURL);
}
}
return null;
}
@Override
public Collection<ConfigAttribute> getAllConfigAttributes() {
return null;
}
@Override
public boolean supports(Class<?> aClass) {
return true;
}
}
~~~
复制
* 每次编辑权限信息后刷新内存中的系统权限信息
~~~
@Autowired
private MySecurityMetadataSource mySecurityMetadataSource;
//重新加载权限
mySecurityMetadataSource.loadResourceDefine();
~~~
- 前言版本&说明
- 概念
- Tceon-PERFOOT 是什么?
- 系统架构
- 主要使用的开源组件
- 角色控制访问权限(RBAC)
- 用户手册
- 系统配置
- 工作流使用配置
- 定时任务调度
- 项目本地运行
- 后端运行
- 前端运行
- 项目结构说明
- 附:使用Oracle等数据库
- 模块化版本
- 后端开发指南
- 基本开发指南
- 前后端数据交互标准
- 工具类及数据权限
- 代码生成器
- 增删改查CRUD
- 日志类型注解扩展
- 逻辑删除
- 各验证码使用及配置
- 前端开发指南
- 基本开发指南
- 主题/Logo/首页等配置
- 路由菜单配置
- 多语言国际化配置
- 自定义图标icon
- 工具类及数据获取
- 完整版开发指南
- 前端Vue代码生成器
- Activiti工作流
- 单点登录配置
- MinIO对象存储服务搭建
- 第三方社交账号配置
- 短信开发/站内消息/邮件
- Vaptcha验证码
- 禁用词使用
- Monaco代码编辑器
- 开放平台及单点登录
- 开放平台使用指南
- Web接入开发流程
- 单点登录开发指南
- 微信小程序端开发指南
- 项目导入与开发必读
- 通用方法工具类说明
- Uniapp端开发指南
- APP后端开发指南
- Uniapp前端开发指南
- 开发新功能示例
- 后端开发新模块
- 前端开发新页面
- 测试
- SonarQube代码质量管理
- TestNG单元测试
- ExtentReports测试报告
- Selenuim自动化Web测试
- Appuim自动化App测试
- JMeter压测性能测试
- 部署
- Spring Boot配置
- 快速部署
- 后端部署
- 前端部署
- 前端部署优化
- Docker容器化部署
- 服务器配置
- DevOps环境搭建
- 组件安装列表
- 开发设计规范
- 分支管理
- 数据库设计规范
- Redis使用规范
- Java基础开发规范
- Rest API规范
- 项目结构规范
- 前端开发规范
- 前端设计规范
- 项目搭建分享
- 后端相关
- SpringBoot 2.x区别总结
- Spring Security整合JWT
- Spring Security动态权限管理
- Spring Boot 2.x整合Quartz
- Spring Boot 2.x整合Websocket
- Spring Boot 2.x整合Activiti工作流以及模型设计器
- Spring Boot + Security全局跨域配置
- 前端相关
- axios请求封装 统一异常处理
- 动态路由菜单加载
- 多维度控制权限至按钮显示
- 发送消息图标红点实时显示
- 动态组件单页操作
- 常见问题