package com.iplatform.security;
|
|
import com.iplatform.base.SecurityConstants;
|
import com.iplatform.base.cache.MenuCacheProvider;
|
import com.walker.infrastructure.utils.StringUtils;
|
import com.walker.security.SystemLogMan;
|
import com.walker.web.Constants;
|
import com.walker.web.security.ResourceLoadProvider;
|
import org.slf4j.Logger;
|
import org.slf4j.LoggerFactory;
|
import org.springframework.security.access.ConfigAttribute;
|
import org.springframework.security.access.SecurityConfig;
|
import org.springframework.security.web.FilterInvocation;
|
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
|
import java.util.ArrayList;
|
import java.util.Collection;
|
import java.util.HashMap;
|
import java.util.Iterator;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.concurrent.ConcurrentHashMap;
|
|
/**
|
* 默认资源加载提供者,security框架需要的权限点集合。
|
* @author 时克英
|
* @date 2022-11-02
|
*/
|
public class DefaultResourceLoaderProvider implements ResourceLoadProvider {
|
|
protected final transient Logger logger = LoggerFactory.getLogger(getClass());
|
|
private MenuCacheProvider menuCacheProvider = null;
|
|
private Map<String, Collection<ConfigAttribute>> resultMap = new HashMap<String, Collection<ConfigAttribute>>();
|
|
/** 请求匹配对象放入Map中,避免重复创建。key = url,value = AntPathRequestMatcher */
|
private Map<String, AntPathRequestMatcher> requestMatchers = new ConcurrentHashMap<String, AntPathRequestMatcher>();
|
|
private Collection<ConfigAttribute> emptyAttributes = null;
|
private Collection<ConfigAttribute> anonymousAttributes = null;
|
// 2023-03-21 activiti7工作流必须拦截权限,变态。
|
private Collection<ConfigAttribute> activiti7Attributes = null;
|
|
private List<String> permitAccessUrls = null;
|
|
private Map<String, String> anonymousUrlMap = null;
|
|
/**
|
* 设置可匿名访问的公开地址集合,如: ["/login","/register", "/image/**"]
|
* @param anonymousUrlList
|
*/
|
public void setAnonymousUrlList(List<String> anonymousUrlList) {
|
if(!StringUtils.isEmptyList(anonymousUrlList)){
|
this.anonymousUrlMap = new HashMap<>();
|
for(String url : anonymousUrlList){
|
this.anonymousUrlMap.put(url, StringUtils.EMPTY_STRING);
|
}
|
}
|
}
|
|
/**
|
* 设置一些只要认证用户都可以访问的常用url,如: /api/**, /report/** 等
|
* @param permitAccessUrls
|
*/
|
public void setPermitAccessUrls(List<String> permitAccessUrls) {
|
this.permitAccessUrls = permitAccessUrls;
|
}
|
|
public void setMenuCacheProvider(MenuCacheProvider menuCacheProvider) {
|
SystemLogMan.getInstance().checkMan();
|
this.menuCacheProvider = menuCacheProvider;
|
}
|
|
@Override
|
public Map<String, Collection<ConfigAttribute>> loadResource() {
|
resultMap.clear();
|
requestMatchers.clear();
|
|
// 1-把菜单和功能点url角色关系整理到对象中:urlRoleMap
|
Map<String, List<String>> urlRoleMap = new HashMap<String, List<String>>();
|
|
// 2-所有角色对应的URL都加入
|
List<String[]> roleUrlMap = this.menuCacheProvider.getAllRoleMenuMap();
|
if(roleUrlMap != null && roleUrlMap.size() > 0){
|
String url = null;
|
for(String[] entry : roleUrlMap){
|
url = entry[1];
|
if(StringUtils.isEmpty(url)){
|
throw new NullPointerException("url is not null! role = " + entry[0]);
|
}
|
setUrlRoleMap(urlRoleMap, url, entry[0]);
|
}
|
}
|
|
// 3-超级管理员默认加上所有菜单权限
|
List<String> allMenuUrl = this.menuCacheProvider.getAllMenuUrlList();
|
if(!StringUtils.isEmptyList(allMenuUrl)){
|
for(String url : allMenuUrl){
|
setUrlRoleMap(urlRoleMap, url, SecurityConstants.ROLE_SUPER_ADMIN);
|
}
|
}
|
setUrlRoleMap(urlRoleMap, "/supervisor/**", SecurityConstants.ROLE_SUPER_ADMIN);
|
// setUrlRoleMap(urlRoleMap, "/wf/**", SecurityConstants.ROLE_SUPER_ADMIN);
|
|
// 4-所有已登录用户,都可以访问默认公开地址: /permit
|
setUrlRoleMap(urlRoleMap, "/permit/**", SecurityConstants.ROLE_USER);
|
|
// 5-其他一些可用地址,已认证用户都可以访问,无需单独配置权限
|
if(!StringUtils.isEmptyList(this.permitAccessUrls)){
|
for(String url : this.permitAccessUrls){
|
setUrlRoleMap(urlRoleMap, url, SecurityConstants.ROLE_USER);
|
// logger.debug("公共访问资源:" + url);
|
// logger.debug(urlRoleMap.toString());
|
}
|
}
|
|
// 6-匿名URL不拦截
|
if(this.anonymousUrlMap != null){
|
for(String url : this.anonymousUrlMap.keySet()){
|
setUrlRoleMap(urlRoleMap, url, Constants.ROLE_ANONYMOUS);
|
}
|
}
|
|
// 7-activiti7工作流权限,必须加上。2023-03-21
|
this.setUrlRoleMap(urlRoleMap, "/wf/**", Constants.ROLE_ACTIVITI_USER);
|
|
logger.info("共加载权限点: " + urlRoleMap.size());
|
// if(logger.isDebugEnabled()){
|
// for(Map.Entry<String, List<String>> entry : urlRoleMap.entrySet()){
|
// logger.debug(entry.getKey() + " = " + entry.getValue());
|
// }
|
// }
|
|
// 6-转成spring security 特定权限属性
|
if(urlRoleMap.size() > 0){
|
List<ConfigAttribute> caList = null;
|
for(Map.Entry<String, List<String>> entry : urlRoleMap.entrySet()){
|
caList = new ArrayList<ConfigAttribute>(entry.getValue().size()+1);
|
for(String s : entry.getValue()){
|
ConfigAttribute ca = new SecurityConfig(s);
|
caList.add(ca);
|
}
|
resultMap.put(entry.getKey(), caList);
|
}
|
}
|
|
// 7-初始化请求路径匹配校验对象
|
Iterator<String> it = resultMap.keySet().iterator();
|
String resURL = null;
|
AntPathRequestMatcher requestMatcher = null;
|
while(it.hasNext()){
|
resURL = it.next();
|
requestMatcher = requestMatchers.get(resURL);
|
// 把requestMatcher对象放到Map中,避免重复创建
|
if(requestMatcher == null){
|
requestMatcher = new AntPathRequestMatcher(resURL);
|
requestMatchers.put(resURL, requestMatcher);
|
}
|
}
|
return resultMap;
|
}
|
|
@Override
|
public void reloadResource() {
|
this.loadResource();
|
logger.info("ResourceLoaderProvider reload success!");
|
}
|
|
@Override
|
public Collection<ConfigAttribute> getAttributes(Object object) {
|
if(resultMap == null) return getEmptyAttributes();
|
|
Iterator<String> it = resultMap.keySet().iterator();
|
|
String srcURL = null;
|
String resURL = null;
|
AntPathRequestMatcher requestMatcher = null;
|
|
while(it.hasNext()){
|
resURL = it.next();
|
requestMatcher = requestMatchers.get(resURL);
|
// 把requestMatcher对象放到Map中,避免重复创建
|
if(requestMatcher == null){
|
requestMatcher = new AntPathRequestMatcher(resURL);
|
requestMatchers.put(resURL, requestMatcher);
|
}
|
srcURL = ((FilterInvocation)object).getRequestUrl();
|
if(requestMatcher.matches(((FilterInvocation)object).getRequest())){
|
logger.debug("............> 找到了匹配的资源: " + resURL + ", 请求的资源: " + srcURL);
|
// 2023-03-21 activiti7修改,当访问流程相关功能,给予流程专用角色
|
// 这是activiti7机制需要的,变态!
|
if(resURL.startsWith(SecurityConstants.URL_WORKFLOW_PREFIX)){
|
logger.debug("返回activiti7的角色集合");
|
return this.getActiviti7Attributes();
|
}
|
return resultMap.get(resURL);
|
}
|
}
|
|
// 2022-11-13
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
// 如果通过表达式没有匹配到URL,这里要检查是否匿名路径
|
// 注意:不能把判断放在前面,因为用户配置匿名地址可能带有通配符,如:/nano/**
|
// 但是这里request获得的URI是特定地址,如: /nano/123
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
if(this.anonymousUrlMap != null && this.anonymousUrlMap.get(srcURL) != null){
|
return this.getAnonymousAttributes();
|
}
|
|
// 如果根据URL没有找到对应的角色集合,就返回一个空集合;
|
// 因为spring security默认对于空集合都放行。
|
return getEmptyAttributes();
|
}
|
|
@Override
|
public Collection<ConfigAttribute> getAttributesByUri(String uri) {
|
return null;
|
}
|
|
private void setUrlRoleMap(Map<String, List<String>> urlRoleMap, String _url, String _roleId){
|
List<String> _roles = urlRoleMap.get(_url);
|
if(_roles == null){
|
_roles = new ArrayList<String>(8);
|
_roles.add(_roleId);
|
urlRoleMap.put(_url, _roles);
|
} else if(!_roles.contains(_roleId)){
|
_roles.add(_roleId);
|
}
|
}
|
|
protected Collection<ConfigAttribute> getEmptyAttributes(){
|
if(emptyAttributes == null){
|
emptyAttributes = new ArrayList<ConfigAttribute>(2);
|
emptyAttributes.add(new SecurityConfig(Constants.ROLE_EMPTY));
|
}
|
return emptyAttributes;
|
}
|
protected Collection<ConfigAttribute> getAnonymousAttributes(){
|
if(anonymousAttributes == null){
|
anonymousAttributes = new ArrayList<ConfigAttribute>(2);
|
anonymousAttributes.add(new SecurityConfig(Constants.ROLE_ANONYMOUS));
|
}
|
return emptyAttributes;
|
}
|
|
/**
|
* 返回Activiti7需要的角色集合。
|
* @return
|
* @date 2023-03-21
|
*/
|
protected Collection<ConfigAttribute> getActiviti7Attributes(){
|
if(this.activiti7Attributes == null){
|
activiti7Attributes = new ArrayList<ConfigAttribute>(2);
|
activiti7Attributes.add(new SecurityConfig(Constants.ROLE_ACTIVITI_USER));
|
}
|
return this.activiti7Attributes;
|
}
|
}
|