Skip to content

Commit

Permalink
细化Spring Security授权服务的代码注释
Browse files Browse the repository at this point in the history
  • Loading branch information
ysc committed Apr 15, 2013
1 parent 5e7a864 commit c9dd478
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,10 @@
import java.util.Stack;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;

/**
* 模块服务
* @author 杨尚川
*/
@Service
public class ModuleService {
protected static final APDPlatLogger log = new APDPlatLogger(ModuleService.class);
Expand Down Expand Up @@ -289,39 +292,71 @@ public void displayControl(List<Module> modules) {
}
}
}

/**
* 获取命令访问路径到角色名称的映射
* 规则:
* 1、去掉开头的/**
* 2、把/转换为_
* 3、把!转换为_
* 3、全部字母转换为大写
* @param command
* @return
*/
public static Map<String, String> getCommandPathToRole(Command command) {
Map<String, String> result = new HashMap<>();
//命令路径:/**/security/user!query
//映射角色:_SECURITY_USER_QUERY
for (String path : getCommandPath(command)) {
String role = path.toString().substring(3).replace("/", "_").replace("!", "_").toUpperCase();
result.put(path, role);
}

return result;
}

/**
* 获取浏览器要访问一个命令的完全路径
* @param command 命令
* @return 因为命令的依赖关系,可能会返回多个路径
*/
public static List<String> getCommandPath(Command command) {
List<String> result = new ArrayList<>();
//command.update=updatePart,updateWhole 表示把update权限分配给用户的时候,用户自动获得updatePart,updateWhole的权限
//update只是一个逻辑的命令,用于统一指定一组命令,方便授权
String dependency = PropertyHolder.getProperty("command." + command.getEnglish());
String[] commands = null;
if (dependency != null && !"".equals(dependency.trim())) {
commands = dependency.split(",");
} else {
commands = new String[]{command.getEnglish()};
}

//APDPlat是支持任意多级的模块嵌套的,虽然目前的DEMO中只有两级
//对于以下的路径来说:
//http://apdplat.net/security/user!query.action
//query是命令
//user是模块
//security也是模块

//倒数第一级模块,对以上例子来说,即为user模块
Module module = command.getModule();
//上下文不把大写字母转换为小写字母+_
//String modulePath = PrivilegeUtils.process(getModulePath(module.getParentModule()));
//获取除了倒数第一级模块之外的模块访问路径表示,对以上例子来说,即为security/
String modulePath = getModulePath(module.getParentModule());
//对模块名称进行处理,如:updatePart要转换为update-part,以符合struts2的规则,对以上例子来说,即为user
String moduleName = PrivilegeUtils.process(module.getEnglish());
for (String cmd : commands) {
StringBuilder path = new StringBuilder();
//模块访问路径+模块名称+"!"+命令 即为浏览器要访问一个命令的完全路径
//如: /**/security/user!query
path.append("/**/").append(modulePath).append(moduleName).append("!").append(cmd);
result.add(path.toString());
}
return result;
}

/**
* 获取该模块在浏览器中的访问路径表示
* @param module
* @return
*/
public static String getModulePath(Module module) {
StringBuilder str = new StringBuilder();
Stack<Module> stack = new Stack<>();
Expand All @@ -332,7 +367,11 @@ public static String getModulePath(Module module) {
}
return str.toString();
}

/**
* 用栈来表示模块的层级关系,从栈顶到栈底就像模块的依赖树一样
* @param module
* @param stack
*/
private static void getModules(Module module, Stack<Module> stack) {
//将当前模块加入堆栈
stack.push(module);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
import org.springframework.stereotype.Service;

/**
*
*Spring Security授权服务
* @author 杨尚川
*/
@Service
Expand Down Expand Up @@ -74,25 +74,50 @@ public void initSecurityConfigInfo(){
log.info("当前系统禁用安全机制");
return ;
}


log.info("开始初始化权限子系统...");
//核心对象,一切url和角色的绑定都围绕它进行
//指定了哪些url可以由哪些角色来访问
LinkedHashMap<RequestKey, Collection<ConfigAttribute>> requestMap =new LinkedHashMap<>();


//普通管理员
SecurityConfig manager=new SecurityConfig("ROLE_MANAGER");
//超级管理员
SecurityConfig superManager=new SecurityConfig("ROLE_SUPERMANAGER");
//value具有超级管理员 或是 普通管理员权限
//这里需要注意 文本大写表示的角色标识 要转换为ConfigAttribute的集合
//在绑定url路径和角色的关系的时候,url路径还分GET和POST两种情况
Collection<ConfigAttribute> value=new ArrayList<>();
value.add(manager);
value.add(superManager);


//1、处理特殊的url访问规则
//urls里面存放了特殊的URL访问规则
Collection<String> urls=new LinkedHashSet<>();
//urlFiles为多个文本文件
String[] urlFiles=PropertyHolder.getProperty("manager.default.url").split(",");
for(String urlFile : urlFiles){
//获取url访问规则文本文件的内容
Collection<String> url=FileUtils.getClassPathTextFileContent(urlFile);
urls.addAll(url);
}
//url为这样的格式:
//格式1:/**/login.jsp*=ROLE_ANONYMOUS,ROLE_MANAGER,ROLE_SUPERMANAGER
//格式2:/**/platform/**
//格式1含义解释:匿名用户、普通管理员、超级管理员都可以访问的路径
//格式2含义解释:超级管理员 或是 普通管理员都可以访问的路径
for(String url : urls){
//格式1:url中指定了只有特定角色才能访问
if(url.contains("=")){
String[] attr=url.split("=");
//真正的url
url=attr[0];
//可有多个角色
String[] roles=attr[1].split(",");
//把多个角色转换为ConfigAttribute的集合
Collection<ConfigAttribute> v=new ArrayList<>();
for(String role : roles){
v.add(new SecurityConfig(role));
Expand All @@ -103,7 +128,9 @@ public void initSecurityConfigInfo(){
//GET
key=new RequestKey(url,"GET");
requestMap.put(key, v);
}else{
}
//格式2:超级管理员 或是 普通管理员都可以访问
else{
//POST
RequestKey key=new RequestKey(url,"POST");
requestMap.put(key, value);
Expand All @@ -113,12 +140,19 @@ public void initSecurityConfigInfo(){
}
}


//2、动态指定系统中模块及命令的url访问规则
//遍历所有的Command对象
for(Command command : serviceFacade.query(Command.class).getModels()){
List<String> paths=ModuleService.getCommandPath(command);
//命令访问路径到角色名称的映射
Map<String,String> map=ModuleService.getCommandPathToRole(command);
for(String path : paths){
//POST
RequestKey key=new RequestKey(path.toString().toLowerCase()+".action*","POST");
value=new ArrayList<>();
//要把路径转换为角色
//如:命令路径:/**/security/user!query 映射角色:_SECURITY_USER_QUERY
value.add(new SecurityConfig("ROLE_MANAGER"+map.get(path)));
value.add(superManager);
requestMap.put(key, value);
Expand All @@ -127,11 +161,16 @@ public void initSecurityConfigInfo(){
requestMap.put(key, value);
}
}

//3、超级管理员对所有的POST操作具有权限
RequestKey key=new RequestKey("/**","POST");
//value为超级管理员
value=new ArrayList<>();
value.add(superManager);
requestMap.put(key, value);
//GET


//4、超级管理员对所有的GET操作具有权限
key=new RequestKey("/**","GET");
requestMap.put(key, value);

Expand Down
4 changes: 2 additions & 2 deletions APDPlat_Core/src/main/resources/org/apdplat/config.properties
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,10 @@ log.create=false
log.delete=false
log.update=false

#\u53ea\u6709\u7528\u6237\u4e00\u65e6\u767b\u9646\u6210\u529f\u4e4b\u540e\u5c31\u53ef\u4ee5\u8bbf\u95ee\u7684URL\u5217\u8868
#\u7279\u6b8a\u7684URL\u8bbf\u95ee\u89c4\u5219\uff0c\u53ef\u7528,\u5206\u5272\uff0c\u6307\u5b9a\u591a\u4e2a\u6587\u4ef6
manager.default.url=org/apdplat/url.txt
#\u67d0\u4e00\u4e2a\u903b\u8f91\u547d\u4ee4\u7684\u5b8c\u6210\u9700\u8981\u5177\u4f53\u7684\u547d\u4ee4\u7ec4\u5408\u5728\u4e00\u8d77\u624d\u80fd\u5b8c\u6210\uff0c\u6bd4\u5982\u8bf4\uff0c\u4fee\u6539\u6570\u636e\u7684\u547d\u4ee4\u5fc5\u987b\u7531\u4e24\u4e2a\u547d\u4ee4\u7ec4\u6210\uff1a1\u3001\u67e5\u8be2\u4e00\u6761\u6570\u636e\uff1b2\u3001\u66f4\u65b0\u4fee\u6539\u4e4b\u540e\u7684\u6570\u636e
#command.*1=c1,c2 \u8868\u793a\u628a*1\u6743\u9650\u5206\u914d\u7ed9\u7528\u6237\u7684\u65f6\u5019\uff0c\u7528\u6237\u81ea\u52a8\u83b7\u5f97c1,c2\u7684\u6743\u9650
#*1\u53ea\u662f\u4e00\u4e2a\u903b\u8f91\u7684\u547d\u4ee4\uff0c\u7528\u4e8e\u7edf\u4e00\u6307\u5b9a\u4e00\u7ec4\u547d\u4ee4\uff0c\u65b9\u4fbf\u6388\u6743
command.update=updatePart,updateWhole
command.query=query,retrieve,search

Expand Down

0 comments on commit c9dd478

Please sign in to comment.