回顾
Shiro安全框架
认证,授权,加密,会话管理(单点登录),缓存,与web集成
单点登录(SSO Single Sign on)的原理
就是将原有的各个系统的会话管理机制,抽取出来交给第三方集中实现,这样在访问其 它每个系统时,只要从第三方管理的会话信息中,获取用户信息,如果正确,就可以不 用再次登录而直接进入系统,这样就可以省去很多登录的时间,从而提高工作效率。
用户-角色分配
UserAction.torole() 进入角色分配页面
/**
* 进入角色分配页面
* @return
* @throws Exception
*/
public String torole() throws Exception {
//1.根据id,得到对象
User obj = userService.get(User.class, model.getId());
//2.将对象保存到值栈中
super.push(obj);
//3.调用角色业务方法,得到角色列表
List<Role> roleList = roleService.find("from Role ", Role.class, null);
//4.将roleList放入值栈
super.put("roleList", roleList);
//5.得到当前用户的角色列表
Set<Role> roleSet = obj.getRoles();
StringBuilder sb = new StringBuilder();
for(Role role :roleSet){
sb.append(role.getName()).append(","); //管理员,船运经理,
}
//6.当前用户的角色字符串放入值栈中
super.put("roleStr", sb.toString());
return "torole";
}
UserAction.role() 实现角色分配
/**
* 实现角色分配
* <input type="hidden" name="id" value="58b537be-2eea-4dee-bc90-f73032476fd6"/>----model.id
*
* <input type="checkbox" name="roleIds" value="4028a1c34ec2e5c8014ec2ebf8430001" class="input"
>
<input type="checkbox" name="roleIds" value="4028a1c34ec2e5c8014ec2ebf8430001" class="input"
>
*/
public String role() throws Exception {
//1.根据用户的id,得到对象
User obj = userService.get(User.class, model.getId());
//2.有哪些角色?只要遍历roleIds,就知道了
Set<Role> roles = new HashSet<Role>();//当前选中的角色列表
for(String id :roleIds){
Role role = roleService.get(Role.class, id);
roles.add(role);//向角色列表中添加一个新的角色
}
//3.设置用户与角色列表之间的关系
obj.setRoles(roles);
//4.保存到数据库表中
userService.saveOrUpdate(obj);//影响的是用户角色的中间表
//5.跳页面
return "alist";
}
private String []roleIds;//保存角色的列表
public void setRoleIds(String[] roleIds) {
this.roleIds = roleIds;
}
sysadmin/user/jUserRole.jsp
<div style="text-align:left">
<c:forEach items="${roleList}" var="o">
<span style="padding:3px;">
<input type="checkbox" name="roleIds" value="${o.id}" class="input"
<c:if test="${fn:contains(roleStr,o.name)}">checked</c:if>
>
${o.name}
</span>
</c:forEach>
</div>
角色-模块分配(权限分配)
思路分析:
1.引入ztree树
2.引入相关的js文件到项目中
sysadmin/role/jRoleModule.jsp
3.在相关的jsp页面上引入这些js文件及css样式
<link rel="stylesheet" href="${ctx }/components/zTree/css/zTreeStyle/zTreeStyle.css" type="text/css" />
<script type="text/javascript" src="${ctx }/components/zTree/js/jquery-1.4.4.min.js"></script>
<script type="text/javascript" src="${ctx }/components/zTree/js/jquery.ztree.core-3.5.min.js"></script>
<script type="text/javascript" src="${ctx }/components/zTree/js/jquery.ztree.excheck-3.5.min.js"></script>
4编写相关的js代码,实现动态生成一颗树(数据来源是ajax)
5分析 进入模块分配页面
tomodule()
/**
* 进入模块分配页面
*
*/
public String tomodule() throws Exception {
//1.根据角色id,得到角色对象
Role obj = roleService.get(Role.class, model.getId());
//2.保存值栈中
super.push(obj);
//跳页面
return "tomodule";
}
6.RoleAction.tomodule() 中添加的方法
7 .配置结果视图
pages/sysadmin/role/jRoleModule.jsp
<div>
<ul id="jkTree" class="ztree">
</ul>
</div>
8.RoleAction中用于处理ajax请求的方法
/**
* 为了使用 zTree树,就要组织好zTree树所使用的json数据
* json数据结构如下:
* [{"id":"模块的id","pId":"父模块id","name":"模块名","checked":"true|false"},{"id":"模块的id","pId":"父模块id","name":"模块名","checked":"true|false"}]
*
* 常用的json插件有哪些?
* json-lib fastjson struts-json-plugin-xxx.jar,手动拼接
*
* 如何输出?
* 借助于response对象输出数据
*/
public String roleModuleJsonStr() throws Exception{
//1.根据角色id,得到角色对象
Role role = roleService.get(Role.class, model.getId());
//2.通过对象导航方式,加载出当前角色的模块列表
Set<Module> moduleSet = role.getModules();
//3.加载出所有的模块列表
List<Module> moduleList = moduleService.find("from Module", Module.class, null);
int size=moduleList.size();
//4.组织json串
StringBuilder sb = new StringBuilder();
sb.append("[");
for(Module module :moduleList){
size--;
sb.append("{\"id\":\"").append(module.getId());
sb.append("\",\"pId\":\"").append(module.getParentId());
sb.append("\",\"name\":\"").append(module.getName());
sb.append("\",\"checked\":\"");
if(moduleSet.contains(module)){
sb.append("true");
}else{
sb.append("false");
}
sb.append("\"}");
if(size>0){
sb.append(",");
}
}
sb.append("]");
//5.得到response对象
HttpServletResponse response = ServletActionContext.getResponse();
response.setContentType("application/json;charset=UTF-8");
response.setHeader("Cache-Control", "no-cache");
//6.使用 response对象输出json串
response.getWriter().write(sb.toString());
//7.返回NONE
return NONE;
}
9.客户端接收json串并加载到ztree
var zTreeObj;
var setting = {
check : {
enable : true
},
data : {
simpleData : {
enable : true
}
}
};
$(document).ready(function() {
$.post(
"${ctx}/sysadmin/roleAction_roleModuleJsonStr.action",
{"id":"${id}"},
function(data){
zTreeObj = $.fn.zTree.init($('#jkTree'), setting, data); //jkTree 树的id,支持多个树
zTreeObj.expandAll(true); //展开所有树节点
},
"json"
);
});
10.如何获取zTree树上被选中的结点?
//获取所有选择的节点
function submitCheckedNodes() {
var nodes = new Array();
nodes = zTreeObj.getCheckedNodes(true); //取得选中的结点
var str = "";
for (i = 0; i < nodes.length; i++) {
if (str != "") {
str += ",";
}
str += nodes[i].id;
}
$('#moduleIds').val(str);
}
11.RoleAction.module()如何保存用户选中的结点。
/**
* 保存当前角色的模块列表
* <input type="hidden" name="id" value="${id}"/>
<input type="hidden" id="moduleIds" name="moduleIds" value="" />
*
*/
public String module() throws Exception {
//1.哪个角色?
Role role = roleService.get(Role.class, model.getId());
//2.选中的模块有哪些?
String ids [] = moduleIds.split(",");
//加载出这些模块列表
Set<Module> moduleSet = new HashSet<Module>();
if(ids!=null && ids.length>0){
for(String id :ids){
moduleSet.add(moduleService.get(Module.class, id));//添加选中的模块,放到模块列表中
}
}
//3.实现角色分配新的模块
role.setModules(moduleSet);
//4.保存结果
roleService.saveOrUpdate(role);
//5.跳页面
return "alist";
}
private String moduleIds;
public void setModuleIds(String moduleIds) {
this.moduleIds = moduleIds;
}
12 .异常框架
如何使用struts2更好的处理异常? 操作步骤:
1.自定义相关异常类
cn.itcast.jk.exception.SysException
public class SysException extends Exception {
private String message;
public SysException(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
}
2.导入异常处理页面 error.jsp
<div id="content" style="text-align:left;">
<table>
<tr>
<td><img alt="system internal error" src="${pageContext.request.contextPath }/images/error01.jpg"/></td>
<br>
<b>错误信息:</b>
<div style="color:blue;padding:15px;">
<s:property value="exception.message"/>
</div>
<button onclick="history.back();">返回</button>
<p><a href="#" onclick="showDetail();">点击这里查看具体错误消息</a>,
<br/>
报告以下错误消息给系统管理员,可以更加快速的解决问题;
<br/>联系电话:120
</p>
</td>
</tr>
</table>
<div id="detail_system_error_msg" style="display:none;text-align:left;padding-bottom:100px;">
<pre><s:property value="exceptionStack"/></pre>
</div>
</div>
3.在struts.xml文件中配置
<package name="default" namespace="/" extends="struts-default">
<global-results>
<result name="error">/WEB-INF/pages/error.jsp</result>
</global-results>
<!-- 全局异常处理 -->
<global-exception-mappings>
<exception-mapping result="error" exception="cn.itcast.jk.exception.SysException"></exception-mapping>
<exception-mapping result="error" exception="java.lang.Exception"></exception-mapping>
</global-exception-mappings>
</package>
粗粒度权限控制:
只能控制不同角色的用户登录系统时,他们所看到的主菜单,左侧菜 单,按钮,超链接是不同的。
目前可以实现顶部菜单,左侧菜单的控制,将来还可以细化到页面上的超链接
细粒度权限控制
在可以控制顶部菜单,左侧菜单,超链接的基础上,可以进一步控制数据。
1.自己添加的记录自己可以看到
2.部门经理可以看到该部门员工所添加的记录(不包括下属部门)
3.总经理可以看到所有记录
思考:
4.部门经理可以看到该部门及下属部门员工所添加的记录
5.副总的角色,可以做到跨部门跨人员
细粒度权限控制实现原理分析
副总
管理本部门及下属部门
购销合同列表查看时,细粒度权限控制
部门成员看到自己的合同-4
部门经理看到本部门的-3
上级主管看到下属部门的-2
分管副总专门看对应的权限(可以看具体哪个部门或者员工的数据)-1
总经理-0
cn.itcast.jk.action.cargo.ContractAction
/**
* 分页查询
*/
public String list() throws Exception {
String hql = "from Contract where 1=1 ";
//如何确定出用户的等级
User user = super.getCurUser();
int degree = user.getUserinfo().getDegree();
if(degree==4){
//说明是员工
hql+=" and createBy='"+user.getId()+"'";
}else if(degree==3){
//说明是部门经理,管理本部门
hql+=" and createDept='"+user.getDept().getId()+"'";
}else if(degree==2){
//说明是管理本部门及下属部门?????
}else if(degree==1){
//说明是副总?????
}else if(degree==0){
//说明是总经理
}
contractService.findPage(hql, page, Contract.class, null);
//设置分页的url地址
page.setUrl("contractAction_list");
//将page对象压入栈顶
super.push(page);
return "list";
}