- 浏览: 69591 次
- 性别:
- 来自: 绍兴
最新评论
这个功能的思路是自己原创的,没看过其他例子,其实是在做之前网上搜了很多也没个可以参考的例子.主要技术是后台springsecurity做拦截判断,前台Extjs4做按钮动态渲染.如果你不了解springsecrity,那你可以先看下我的另一篇相关博客
创建数据库表(liqiubase方式创建看上一篇)
这张是权限表,也是菜单(按钮)表,每个菜单都有他自己需要访问链接的权限,当菜单类型为子菜单或按钮时还需要配置该按钮对应的js文件,对没错,每个按钮都有自己独立的js文件,在用户没有按钮权限的时候,前端是js都不需要加载的
添加菜单初始数据
添加了一个父级菜单用户管理,两个子集菜单账号管理和角色管理,同时在账号管理下添加两个按钮新增和修改,需要注意的是新增的授权链接是account!save.action而修改的授权链接是account!save.action,account!find.action,因为修改需要先查再能改,当用户被授予新增和修改两个权限的时候,访问account!save.action,account!find.action也就不会受阻了
创建角色表和角色权限关联表
角色和权限是多对多的关系,一个角色可以有多个权限,一个权限也可以属于多个角色,
配完初始数据以后前台展示大致是这样的(图片太大请在新窗口打开)
拥有角色管理的的用户可以添加删除角色,同时可以为没每个角色分配权限
创建用户角色关联表
这里给admin初始化了id为1的角色,也就是超级管理员,同样
拥有账号管理里的用户可以为账号添加角色
到这里数据的配置基本讲完了,再展示下初始数据的liqiubase文件,大致就是那几张表,
最后我再给游客2分配了几个权限,新增一个角色为游客2的账号
以上展示的只是数据配置的过程,通俗的讲就是想法,
现在想法已经出来了,权限也分配好了真正的权限控制核心代码就开始了,首先展示下我的hibernate entity
Account作为springsecrity的账户类必须实现UserDetails接口,实现的getAuthorities方法是告诉spring当前用户的角色,还有个自定义方法getSignPer用于获取当前用户的权限列表,Permission类有个方法getControlTypeByDg通过配置的jsUrl链接获取Extjs的组件类名,他们的用处后面就能看到,这里补充下我用的是Hibernate的注解方式,严格来讲项目中除了公共配置部分,其他包括Struts Spring等需要xml配置的我全用了注解,如果你对注解不是很了解用xml配置的形式也是可以的
用户通过springsecrity登录成功的时候,会把Account对象保存它的上下文,然后访问这个跳转到主页的action方法,action方法中从springsecrity上下文中获取到Account后通过getSignPer方法获取当前用户的权限(也就是菜单),下面就是用户cccq3y的菜单了
当用户点击新增确认按钮时,浏览器会向后台提交一个表单,url为account!save.action,首先会被springsecrity的MyFilterInvocationSecurityMetadataSource拦截到
返回的角色中应该有一个是游客2的id,然后再被MyAccessDecisionManager拦截到
注释写个很清楚了,把当前用户所拥有的角色和MyFilterInvocationSecurityMetadataSource返回的访问当前链接需要哪些角色,如果包含说明当前用户能访问该链接了,再没抛AccessDeniedException错误的情况下验证都通过
最后再说下前端代码,首先主页的jsp要根据权限加载js文件
然后来感受下extjs4的强大之处了,首先我封装一个公共的权限工具条
然后是grid基类
把当前组件的xtype作为参数,到后台获取对应的父级菜单,再根据用户拥有的按钮权限获取这个用户在当前组件的按钮权限,那么问题来了,我是如果通过xtype定位到那条权限数据的呢,真相是我在配置账号管理这个权限的时候配置的jsUrl为user/account/searchGrid然后通过上面Permission类自定义的getControlTypeByDg方法转成xtype,再来看看我的grid子类就清楚了
alias:widget.userAccountSearchGrid,这样就能和后台的权限做对应了,而且在点击菜单树的时候同样用到这个功能,我会根据当前被点击菜单的jsUrl属性转义成xtype,然后很方便的加载对应的组件,就这么简单.最后展示下我的js文件目录
写到这里差不多就结束了,写的有点乱,看不懂的可以加我qq探讨一下;
创建数据库表(liqiubase方式创建看上一篇)
<createTable tableName="permissions"> <column name="id" type="bigint"> <constraints nullable="false" primaryKey="true" /> </column> <!-- 权限名称 --> <column name="name" type="varchar(32)" /> <!-- 该权限需要访问的链接 --> <column name="actionurl" type="varchar(256)" /> <!-- 该权限需要用到的js --> <column name="jsurl" type="varchar(256)" /> <!-- 权限等级 1主菜单 2子菜单 3及以下按钮 --> <column name="level" type="int" /> <!-- 菜单父级id --> <column name="parentid" type="bigint"/> <!-- 排序编号 --> <column name="ordernum" type="int" defaultValue="0"/> </createTable>
这张是权限表,也是菜单(按钮)表,每个菜单都有他自己需要访问链接的权限,当菜单类型为子菜单或按钮时还需要配置该按钮对应的js文件,对没错,每个按钮都有自己独立的js文件,在用户没有按钮权限的时候,前端是js都不需要加载的
添加菜单初始数据
<insert tableName="permissions"> <column name="id" value="1"/> <column name="name" value="用户管理" /> <column name="level" value="1" /> <column name="parentid" value="-1"/> <column name="ordernum" value="1"/> </insert> <insert tableName="permissions"> <column name="id" value="101"/> <column name="name" value="账号管理" /> <column name="actionurl" value="account!query.action" /> <column name="jsurl" value="user/account/searchGrid" /> <column name="level" value="2" /> <column name="parentid" value="1"/> <column name="ordernum" value="1"/> </insert> <insert tableName="permissions"> <column name="id" value="102"/> <column name="name" value="角色管理" /> <column name="actionurl" value="" /> <column name="jsurl" value="user/role/mainPanel" /> <column name="level" value="2" /> <column name="parentid" value="1"/> <column name="ordernum" value="2"/> </insert> <insert tableName="permissions"> <column name="id" value="1001"/> <column name="name" value="新增" /> <column name="actionurl" value="account!save.action" /> <column name="jsurl" value="user/account/searchGridAddBtn" /> <column name="level" value="3" /> <column name="parentid" value="101"/> <column name="ordernum" value="1"/> </insert> <insert tableName="permissions"> <column name="id" value="1004"/> <column name="name" value="修改" /> <column name="actionurl" value="account!save.action,account!find.action" /> <column name="jsurl" value="user/account/searchGridUpdBtn" /> <column name="level" value="3" /> <column name="parentid" value="101"/> <column name="ordernum" value="1"/> </insert>
添加了一个父级菜单用户管理,两个子集菜单账号管理和角色管理,同时在账号管理下添加两个按钮新增和修改,需要注意的是新增的授权链接是account!save.action而修改的授权链接是account!save.action,account!find.action,因为修改需要先查再能改,当用户被授予新增和修改两个权限的时候,访问account!save.action,account!find.action也就不会受阻了
创建角色表和角色权限关联表
<createTable tableName="roles"> <column name="id" type="bigint"> <constraints nullable="false" primaryKey="true" /> </column> <column name="rolename" type="varchar(32)" /> </createTable> <insert tableName="roles"> <column name="id" value="1" /> <column name="rolename" value="超级管理员" /> </insert> <createTable tableName="role_permission"> <column name="id" type="bigint"> <constraints nullable="false" primaryKey="true" /> </column> <column name="perid" type="bigint" /> <column name="roleid" type="bigint" /> </createTable>
角色和权限是多对多的关系,一个角色可以有多个权限,一个权限也可以属于多个角色,
配完初始数据以后前台展示大致是这样的(图片太大请在新窗口打开)
拥有角色管理的的用户可以添加删除角色,同时可以为没每个角色分配权限
创建用户角色关联表
<createTable tableName="account_role"> <column name="accountid" type="bigint" /> <column name="roleid" type="bigint" /> </createTable> <insert tableName="account_role"> <column name="accountid" value="1" /> <column name="roleid" value="1" /> </insert>
这里给admin初始化了id为1的角色,也就是超级管理员,同样
拥有账号管理里的用户可以为账号添加角色
到这里数据的配置基本讲完了,再展示下初始数据的liqiubase文件,大致就是那几张表,
最后我再给游客2分配了几个权限,新增一个角色为游客2的账号
以上展示的只是数据配置的过程,通俗的讲就是想法,
现在想法已经出来了,权限也分配好了真正的权限控制核心代码就开始了,首先展示下我的hibernate entity
package cn.sdh.entity; import java.io.File; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.JoinTable; import javax.persistence.ManyToMany; import javax.persistence.SequenceGenerator; import javax.persistence.Table; import javax.persistence.Transient; import org.apache.struts2.json.annotations.JSON; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.GrantedAuthorityImpl; import org.springframework.security.core.userdetails.UserDetails; import cn.sdh.common.base.AuditEntity; @SuppressWarnings("serial") @Entity @Table(name="accounts") public class Account extends AuditEntity implements UserDetails { public Account(){ } public Account(Long id, String username, String password, String email,Date lastLoginTime, int userType){ this.id = id; this.username = username; this.password = password; this.email = email; this.lastLoginTime = lastLoginTime; this.userType = userType; } @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_ACCOUNT") @SequenceGenerator(name = "SEQ_ACCOUNT", sequenceName = "SEQ_ACCOUNT", initialValue = 2, allocationSize = 1) @Column(name="id") private Long id; @Column(name="username") private String username; @Column(name="password") private String password; @Column(name="email") private String email; //@Type(type="cn.sdh.common.userType.dateToInt") @Column(name="lastlogintime") private Date lastLoginTime; private int userType;//用户类型-1:超级管理员 0普通用户 1+级用户 //是否在线 @Transient private int isOnLine; //搜索时间 起止 @Transient private Date lastLoginTime1; @Transient private Date lastLoginTime2; @ManyToMany(fetch = FetchType.EAGER) @JoinTable(name="account_role",joinColumns={@JoinColumn(name="accountid")},inverseJoinColumns={@JoinColumn(name="roleid")}) private List<Role> roles = new ArrayList<Role>(); @Transient private File photo; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public List<Role> getRoles() { return roles; } public void setRoles(List<Role> roles) { this.roles = roles; } public Date getLastLoginTime() { return lastLoginTime; } public void setLastLoginTime(Date lastLoginTime) { this.lastLoginTime = lastLoginTime; } /** * 告诉spring当前用户的角色 */ @Override @JSON(serialize=false) public Collection<GrantedAuthority> getAuthorities() { Set<GrantedAuthority> authSet = new HashSet<GrantedAuthority>(); for (Role role : this.getRoles()) { authSet.add(new GrantedAuthorityImpl(role.getId().toString())); } return authSet; } @Override @JSON(serialize=false) public boolean isAccountNonExpired() { return true; } @Override @JSON(serialize=false) public boolean isAccountNonLocked() { return true; } @Override @JSON(serialize=false) public boolean isCredentialsNonExpired() { return true; } @Override @JSON(serialize=false) public boolean isEnabled() { return true; } public Date getLastLoginTime1() { return lastLoginTime1; } public void setLastLoginTime1(Date lastLoginTime1) { this.lastLoginTime1 = lastLoginTime1; } public Date getLastLoginTime2() { return lastLoginTime2; } public void setLastLoginTime2(Date lastLoginTime2) { this.lastLoginTime2 = lastLoginTime2; } public int getUserType() { return userType; } public void setUserType(int userType) { this.userType = userType; } public int getIsOnLine() { return isOnLine; } public void setIsOnLine(int isOnLine) { this.isOnLine = isOnLine; } @JSON(serialize=false) public List<Permission> getSignPer(){ List<Permission> perList = new ArrayList<Permission>(); for(Role role : this.getRoles()){ List<Permission> sublist = role.getPermissionList(); for(int h = 0; h<sublist.size(); h++){ boolean continueFlag = false; for(int j = 0;j<perList.size();j++){ if(role.getPermissionList().get(h).getId()==perList.get(j).getId()){ continueFlag = true; break; } } if(continueFlag){ continue; } if(role.getPermissionList().get(h).getLevel()==2){ role.getPermissionList().get(h).setLeaf(1); } role.getPermissionList().get(h).setChildren(null); //role.getPermissionList().get(h).setControlType(role.getPermissionList().get(h).getControlType()); perList.add(role.getPermissionList().get(h)); } } return perList; } public File getPhoto() { return photo; } public void setPhoto(File photo) { this.photo = photo; } }
package cn.sdh.entity; import java.util.List; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.OneToMany; import javax.persistence.Table; import javax.persistence.Transient; import org.apache.struts2.json.annotations.JSON; import cn.sdh.common.base.AuditEntity; /** * 权限类(菜单,按钮,功能) * @author 孙东辉 */ @Entity @Table(name="permissions") public class Permission extends AuditEntity{ /** * */ private static final long serialVersionUID = 7930766554705439940L; @Id @Column(name="id") private Long id; @Column(name="name") private String name; /** * 访问地址 */ @Column(name="actionurl") private String actionUrl; /** * js文件地址 */ @Column(name="jsurl") private String jsUrl; /** * 等级 1-N */ @Column(name="level") private int level; /** * 父级编号 */ @Column(name="parentid") private Long parentid; /** * 弹出的控件类 */ @Transient private String controlType; @Transient private int leaf; @Transient private boolean checked; @Transient private boolean expanded = true; @OneToMany(fetch=FetchType.EAGER) @JoinColumn(name = "parentid", referencedColumnName="id",insertable=false,updatable=false) private List<Permission> children; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getActionUrl() { return actionUrl; } public void setActionUrl(String actionUrl) { this.actionUrl = actionUrl; } public String getJsUrl() { return jsUrl; } public void setJsUrl(String jsUrl) { this.jsUrl = jsUrl; } public int getLevel() { return level; } public void setLevel(int level) { this.level = level; } public Long getParentid() { return parentid; } public void setParentid(Long parentid) { this.parentid = parentid; } @JSON(name="text") public String getName() { return name; } public void setName(String name) { this.name = name; } public String getControlType() { if(this.jsUrl!=null) return getControlTypeByDg(this.jsUrl); else return this.controlType; } public void setControlType(String controlType) { this.controlType = controlType; } public int getLeaf() { if(this.level==3){ return 1; } return this.leaf; } public void setLeaf(int leaf) { this.leaf = leaf; } public boolean isChecked() { return checked; } public void setChecked(boolean checked) { this.checked = checked; } public List<Permission> getChildren() { return children; } public void setChildren(List<Permission> children) { this.children = children; } public boolean isExpanded() { return expanded; } public void setExpanded(boolean expanded) { this.expanded = expanded; } /** * 通过路径获得组件名称 * @param path * @return */ public String getControlTypeByDg(String path){ if(path.indexOf("/")>=0){ path = path.replaceFirst(path.substring(path.indexOf("/"),path.indexOf("/")+2), path.substring(path.indexOf("/")+1,path.indexOf("/")+2).toUpperCase()); return getControlTypeByDg(path); }else{ return path; } } }
package cn.sdh.entity; import java.util.ArrayList; import java.util.List; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.JoinTable; import javax.persistence.ManyToMany; import javax.persistence.OrderBy; import javax.persistence.SequenceGenerator; import javax.persistence.Table; import org.hibernate.annotations.Fetch; import org.hibernate.annotations.FetchMode; import cn.sdh.common.base.AuditEntity; /** * 角色类 * @author 孙东辉 */ @Entity @Table(name="roles") public class Role extends AuditEntity{ /** * */ private static final long serialVersionUID = 5459879676154477558L; @Id @Column(name="id") @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_ROLE") @SequenceGenerator(name = "SEQ_ROLE", sequenceName = "SEQ_ROLE", initialValue = 100, allocationSize = 1) private Long id; /** * 角色名称 */ @Column(name="rolename") private String roleName; /** * 拥有的权限集合 */ @ManyToMany(fetch = FetchType.EAGER) @Fetch(FetchMode.SUBSELECT) @OrderBy("level") @JoinTable(name="role_permission",joinColumns={@JoinColumn(name="roleid")},inverseJoinColumns={@JoinColumn(name="perid")}) private List<Permission> permissionList = new ArrayList<Permission>(); public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getRoleName() { return roleName; } public void setRoleName(String roleName) { this.roleName = roleName; } public List<Permission> getPermissionList() { return permissionList; } public void setPermissionList(List<Permission> permissionList) { this.permissionList = permissionList; } }
Account作为springsecrity的账户类必须实现UserDetails接口,实现的getAuthorities方法是告诉spring当前用户的角色,还有个自定义方法getSignPer用于获取当前用户的权限列表,Permission类有个方法getControlTypeByDg通过配置的jsUrl链接获取Extjs的组件类名,他们的用处后面就能看到,这里补充下我用的是Hibernate的注解方式,严格来讲项目中除了公共配置部分,其他包括Struts Spring等需要xml配置的我全用了注解,如果你对注解不是很了解用xml配置的形式也是可以的
用户通过springsecrity登录成功的时候,会把Account对象保存它的上下文,然后访问这个跳转到主页的action方法,action方法中从springsecrity上下文中获取到Account后通过getSignPer方法获取当前用户的权限(也就是菜单),下面就是用户cccq3y的菜单了
/** * 跳转到主页 * * @throws JSONException */ public String index() throws JSONException { entity = SpringSecurityUtils.getCurrentUser(); List<Permission> perList = entity.getSignPer(); HttpServletRequest request = ServletActionContext.getRequest(); request.setAttribute("perList", perList); request.setAttribute("perListJson", JSONUtil.serialize(perList)); return "index"; }
当用户点击新增确认按钮时,浏览器会向后台提交一个表单,url为account!save.action,首先会被springsecrity的MyFilterInvocationSecurityMetadataSource拦截到
package cn.sdh.audit; import java.util.Collection; import java.util.HashSet; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.ConfigAttribute; import org.springframework.security.access.SecurityConfig; import org.springframework.security.web.FilterInvocation; import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource; import org.springframework.stereotype.Service; import cn.sdh.common.exception.ServiceException; import cn.sdh.entity.Permission; import cn.sdh.entity.Role; import cn.sdh.service.RoleService; import cn.sdh.utils.MyCacheUtil; /** * 告诉spring当前访问链接 需要什么权限 在这边定义 * @author 孙东辉 * */ @Service public class MyFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource { @Autowired private RoleService roleService; public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException { //这个是当前访问的链接 String requestUrl = ((FilterInvocation) object).getRequestUrl(); //设置哪些页面不需要权限就可访问 if(requestUrl.indexOf("account!index.action") >= 0 || requestUrl.indexOf("index.jsp") >= 0 || requestUrl.indexOf("permission!queryBtnListByControlType.action") >= 0 || requestUrl.indexOf("account!searchOnlineList.action")>=0 || requestUrl.indexOf("queryDicDataByKey.action")>=0){ return null; } // 对于带参数的请求,截取?前面的uri int urlIndex = requestUrl.indexOf("?"); if (urlIndex != -1) { requestUrl = requestUrl.substring(0, urlIndex); } //如果第一位是/ 去掉 if(requestUrl.startsWith("/")){ requestUrl = requestUrl.substring(1); } //从缓存中取当前系统的所有角色 List<Role> roles = (List<Role>) MyCacheUtil.getRolesList(); if(roles == null || roles.size()==0){//如果缓存中没有 try { roles = roleService.query(); //把角色放入缓存 MyCacheUtil.setRolesList(roles); } catch (ServiceException e) { throw new IllegalArgumentException(e.getMsg()); } } Collection<ConfigAttribute> c = new HashSet<ConfigAttribute>(); //遍历所有角色 List<Permission> permissionList = null; if(roles.size()>0){ for(int i = 0;i<roles.size();i++){ permissionList = roles.get(i).getPermissionList(); for(int j = 0;j<permissionList.size();j++){ //如果权限中的actionUrl包含当前访问的链接,当说明现在这个角色是可以访问该链接的 if(permissionList.get(j)!=null&&permissionList.get(j).getActionUrl()!=null&&permissionList.get(j).getActionUrl().indexOf(requestUrl)>=0){ ConfigAttribute configAttribute = new SecurityConfig(roles.get(i).getId()+""); c.add(configAttribute); break; } } } }else{ return null; } //最后返回的是一个角色的集合,并且这些角色都是可以访问该链接的 return c; } public Collection<ConfigAttribute> getAllConfigAttributes() { return null; } public boolean supports(Class<?> clazz) { return true; } }
返回的角色中应该有一个是游客2的id,然后再被MyAccessDecisionManager拦截到
package cn.sdh.audit; import java.util.Collection; import java.util.Iterator; import org.springframework.security.access.AccessDecisionManager; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.access.ConfigAttribute; import org.springframework.security.access.SecurityConfig; import org.springframework.security.authentication.InsufficientAuthenticationException; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; /** * 自定义访问决定器 控制用户能否访问该链接 * @author sun * */ public class MyAccessDecisionManager implements AccessDecisionManager { public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException { //如果访问的页面没有权限限制 那么不做拦截继续访问 如果未空说明该页面不需要任何角色 // 注意这里的configAttributes 其实就是MyFilterInvocationSecurityMetadataSource返回的 if (configAttributes == null) { return; } //如果有权限限制 那么需要迭代权限 验证用户所拥有的权限是否包含 当前页面的访问权限 Iterator<ConfigAttribute> ite = configAttributes.iterator(); while (ite.hasNext()) { //获取访问页面需要的权限 ConfigAttribute ca = ite.next(); //获取访问页面需要的权限的权限名称 String needRole = ((SecurityConfig) ca).getAttribute(); //迭代用户所拥有的权限 for (GrantedAuthority ga : authentication.getAuthorities()) { //如果用户的其中一个权限满足 访问链接需要的其中一个权限,那么访问将继续 if (needRole.equals(ga.getAuthority())) { return; } } } //否则 访问将被终止 throw new AccessDeniedException("没有权限访问"); } public boolean supports(ConfigAttribute attribute) { // TODO Auto-generated method stub return true; } public boolean supports(Class<?> clazz) { // TODO Auto-generated method stub return true; } }
注释写个很清楚了,把当前用户所拥有的角色和MyFilterInvocationSecurityMetadataSource返回的访问当前链接需要哪些角色,如果包含说明当前用户能访问该链接了,再没抛AccessDeniedException错误的情况下验证都通过
最后再说下前端代码,首先主页的jsp要根据权限加载js文件
<!-- 根据权限加载js文件 --> <s:iterator value="#request.perList" var="bean"> <s:if test="#bean.jsUrl!=null"> <script type="text/javascript" src="common/jscode/<s:property value="#bean.jsUrl"/>.js"></script> </s:if> </s:iterator>
然后来感受下extjs4的强大之处了,首先我封装一个公共的权限工具条
/** * 权限按钮工具条 */ Ext.define("app.base.auditbar", { extend : "Ext.toolbar.Toolbar", alias : 'widget.auditbar', initComponent : function() { var me = this; var call = function(){ var sme = me; // 根据组件类型 获取它所有的按钮 Ext.Ajax.request({ url : 'permission!queryBtnListByControlType.action', params : { 'entity.controlType' : me.compont }, success : new app.ajaxHand({ success : function(result,scope) { var btns = result.searchList; for ( var i = 0; i < btns.length; i++) { if(scope){ sme = scope; } sme.insert(i, [ { xtype : btns[i].controlType, text : btns[i].text } ]); } } },sme) }); }; if(me.remote){ call(); } if(me.searchItems){ if(!me.items){ me.items = []; } me.items =me.items.concat(['->', { xtype : "searchItems", items : me.searchItems } ]); } me.callParent(me); } });
然后是grid基类
Ext.define("app.base.grid", { extend : "Ext.grid.Panel", //日期 dateRender : function(){return Ext.util.Format.dateRenderer(app.constant.date_render);}, //日期加时间 datetimeRender : function(){return Ext.util.Format.dateRenderer(app.constant.datetime_render);}, //单元格编辑插件 editingPlugin : function(){ return Ext.create('Ext.grid.plugin.CellEditing',{});}, //行编辑插件 rowEditingPlugin : function(){return Ext.create('Ext.grid.plugin.RowEditing', { clicksToMoveEditor: 1, errorSummary : false, autoCancel: true });}, //行复选框 selModelPlugin : function(){return Ext.create("Ext.selection.CheckboxModel");}, initComponent : function(){ var me = this; if(me.paging){ me.bbar = Ext.create('app.base.paging',{ store:me.store }); } me.tbar = Ext.create('app.base.auditbar',{ compont : me.xtype, searchItems : me.searchItems, remote:me.auditbarEnable, items : me.btns }); this.callParent(); }, //添加行 addRow : function(){ this.store.insert(0,new (Ext.ModelManager.getModel(this.model))); this.editing.cancelEdit(); if(this.editing){ this.editing.startEdit(0,0); } }, //删除行 deleteRow : function(){ var recode = this.getSelectionModel().getSelection(); this.store.remove(recode); }, //验证选中行 checkSelectRow : function(count,tip){ if(!count){ count = 1; } tip = tip || "请"+(count!=1?"至少":"")+"选择一行要删除的记录"; var recode = this.getSelectionModel().getSelection(); if(recode.length==0||(count==1&&recode.length>1)){ app.alert(tip); return false; } var usedata = []; var ids = ""; for(var i = 0;i<recode.length;i++){ usedata.push(recode[i].data); ids += recode[i].data.id; if(i!=recode.length-1){ ids += ","; } } usedata.unshift(ids); return usedata; } });
把当前组件的xtype作为参数,到后台获取对应的父级菜单,再根据用户拥有的按钮权限获取这个用户在当前组件的按钮权限,那么问题来了,我是如果通过xtype定位到那条权限数据的呢,真相是我在配置账号管理这个权限的时候配置的jsUrl为user/account/searchGrid然后通过上面Permission类自定义的getControlTypeByDg方法转成xtype,再来看看我的grid子类就清楚了
Ext.define("app.user.account.searchGrid", { extend : "app.user.account.grid", alias: 'widget.userAccountSearchGrid', initComponent : function(){ var me = this; me.editing = me.rowEditingPlugin(); Ext.apply(this,{ plugins : [me.editing], paging : true, selModel : me.selModelPlugin(), searchItems :[{ fieldLabel : '用户名', xtype : 'textfield', labelAlign : 'right', name : 'entity.username', labelWidth : 45 },{ fieldLabel : '邮箱', xtype : 'textfield', labelAlign : 'right', name : 'entity.email', labelWidth : 45 },{ fieldLabel : '上次登录起', xtype : 'datefield', labelAlign : 'right', name : 'entity.lastLoginTime1', labelWidth : 75 },{ fieldLabel : '上次登录止', xtype : 'datefield', labelAlign : 'right', name : 'entity.lastLoginTime2', labelWidth : 75 }] }); me.callParent(); } });
alias:widget.userAccountSearchGrid,这样就能和后台的权限做对应了,而且在点击菜单树的时候同样用到这个功能,我会根据当前被点击菜单的jsUrl属性转义成xtype,然后很方便的加载对应的组件,就这么简单.最后展示下我的js文件目录
写到这里差不多就结束了,写的有点乱,看不懂的可以加我qq探讨一下;
发表评论
-
Web开发学习13聊聊java反射
2016-07-12 18:41 765很喜欢一本叫《走出软件作坊》的书,其中有一句话让我较为深刻,“ ... -
Web开发学习12 浅谈设计模式
2016-07-01 13:33 1325在我刚接触 ... -
Web开发学习11 全局缓存控制
2015-10-12 14:27 746缓存用的好可以减少数据库的压力,在大并发的情况下极大的提升服务 ... -
Web开发学习10 hadoop实战
2015-10-09 14:02 761前一篇说到项目记录了很多埋点日志,当有一天项目需求需要对这些日 ... -
Web开发学习(9)全局埋点
2015-07-27 11:10 2025埋点的作用是把客户端每次访问服务端的操作记录下来,包括请求连接 ... -
Web开发学习8Struts2基类封装
2015-07-24 12:03 710一个好的基类可以帮助开发者减少很多开发工作,像我这种爱偷懒的人 ... -
Web开发学习6添加liqiubase
2015-07-22 14:29 1466开发过程中经常碰到数据库更改的情况,在日常环境下如果每位开发人 ... -
浅列JavaEnum
2014-01-05 16:42 791enum Province{ ZHEJIANG,SHANGHA ... -
maven常用命令
2013-07-08 10:20 7921、创建普通Java项目: ... -
canvas绘制科赫雪花
2012-12-20 17:24 2161<html> <head> ... -
html5 audio与video方法属性事件概括
2012-12-20 14:46 1124play() 继续播放 pause() ... -
spring 整合mina
2012-12-20 11:48 1122首先定义自定义过滤器 <bean id=" ... -
Web开发学习(5)添加springsecurity应用
2011-12-14 15:00 965我学习公司这个架构多半就是为了把springsecurity搞 ... -
Web开发学习(4)添加spring应用
2011-12-14 14:45 798印象中似乎没做过不用spring的项目,因为它在web开发中的 ... -
Web开发学习(3)配置struts-tiles插件(附带json插件)
2011-12-05 15:22 2573struts的tiles插件是非常实用的,从某些方面可以很好的 ... -
使用线程删除导出临时文件
2011-12-01 16:33 2276项目支持大数据量导出e ... -
jQuery实现表格行点击选中复选框
2011-11-23 12:36 6007这个需求是在项目完成后客户提出的要求,看似简单但是还需要一点小 ... -
Web开发学习(2)配置convention插件
2011-11-04 10:28 1396注解的方式某些程度上能减少xml的配置量,个人感觉使程序更加清 ... -
Web开发学习(1)使用eclipse搭建maven项目
2011-10-20 10:04 5747首先用eclipse创建工程 ne ... -
数据库连接泛型基类创建
2011-06-30 11:49 1000记录 以便以后参考---- 基类代码 public cl ...
相关推荐
本项目"简单的按钮级别权限管理"采用Spring和Hibernate框架,结合MySQL数据库,构建了一个功能完善的权限控制系统。下面将详细阐述这些技术及其在权限管理中的应用。 首先,Spring框架是Java开发中的一个核心工具,...
在按钮级别权限控制中,我们首先要确定的是权限模型。常见的权限模型包括角色基础(Role-Based)、用户基础(User-Based)以及基于资源和操作的权限模型(Resource-Based Permissions)。在这个案例中,我们可能需要...
在现代Web应用开发中,权限控制是至关重要的一个环节,特别是在企业级应用中。Vue3作为一款流行的前端框架,提供了一种高效的方式...在不断变化的Web开发领域,理解和掌握这些技术对于提升开发效率和产品质量至关重要。
在现代Web应用开发中,权限控制是一个至关重要的环节,它涉及到用户访问的权限范围和操作权限,确保系统安全。Vue.js作为一个轻量级的前端框架,搭配Apache Shiro这样的安全管理框架,可以有效地实现前端的细粒度...
按钮权限控制则是在组件级别进行的,这通常涉及到每个按钮的v-if或v-show指令,或者更高级的策略,如使用自定义指令。根据用户的角色和权限,决定是否显示或禁用特定的按钮。这样可以确保用户只能执行他们被授权的...
Vue指令实现按钮级别权限管理功能是一个涉及到前端Vue框架的权限控制技术。在Web开发中,用户权限管理是不可或缺的一部分,它确保了用户界面元素只向符合特定权限条件的用户显示。本文介绍的实现方法,通过Vue指令这...
在IT行业中,Web应用系统的设计和开发是至关重要的部分,其中菜单及权限控制是系统功能的核心组成部分。这个过程涉及到用户界面的组织结构以及不同用户访问和操作系统的权限管理。以下是对"Web应用系统菜单及权限...
在本文中,我们将深入探讨Acegi如何实现精细的权限控制,直至按钮或HTML元素级别,以及如何将其部署到Tomcat服务器。 首先,Acegi的核心是基于Spring AOP(面向切面编程)的安全模型。它允许开发人员定义安全策略,...
在开发Web应用时,权限控制是一项重要的功能,它确保用户只能访问他们被授权的操作和界面。在基于Vue.js的项目中,我们可以通过多种方式实现权限控制,其中之一就是使用自定义指令。本文将深入探讨如何利用Vue自定义...
总的来说,这种基于Vue.js和Django的权限控制方法和系统提高了Web应用的安全性,降低了开发和维护成本,使得权限管理更加灵活和可控。通过前后端的紧密协作,确保了用户只能看到和操作他们被授权的内容,从而保护了...
《php和mysql web开发(原书第4版)》:开发人员专业技术丛书。 目录 读者反馈 译者序 前言 作者简介 第一篇 使用PHP 第1章 PHP快速入门教程 1.1 开始之前:了解PHP 1.2 创建一个示例应用:Bob汽车零部件商店 ...
① 系统除采用 RBAC 模型进行访问控制以外,还配合 Shiro 框架完成系统的鉴权机制,其中 RBAC 负责左侧菜单级别权限, Shiro 负责按钮级别权限。 ② 系统对于添加修改相关操作采用 Validator 完成表单参数的校验,还...
5. 用户界面的交互:如何展示权限控制的结果,如菜单项的显示与否,以及按钮的启用/禁用状态。 总的来说,这个VB.NET系统架构源码提供了实践和学习权限控制的机会,帮助开发者更好地理解和应用.NET Framework的安全...
4. **组件级别的权限**:除了页面级别的权限,LigerUI中还可以实现组件级别的权限控制。例如,某些按钮、字段或选项只对特定用户可见或可操作。 5. **权限检查机制**:在用户尝试执行操作前,需要进行权限检查。这...
在开发Web应用时,权限控制是必不可少的一部分,尤其是在构建后台管理系统中。本教程将深入探讨如何使用Vue.js和element-ui组件库实现一个完善的后台管理系统的权限控制机制。Vue.js是一个轻量级的前端框架,而...
是一个简单高效的后台权限管理系统。...安全框架采用时下流行的Apache Shiro,可实现对按钮级别的权限控制;前端页面使用Bootstrap构建,主题风格为时下Google最新设计语言Material Design,并提供多套配色以供选择。
在SpringBoot应用中,Shiro 可以与Spring的AOP机制结合,实现细粒度的权限控制,如URL级别的访问权限。 在这个架构中,Vue.js 和 Element UI 负责前端展示和交互,用户登录、权限相关的操作通过Ajax请求发送到后端...
安全框架采用Shiro,可实现对按钮级别的权限控制,前端页面使用LayUI构建,主题风格小清新简洁, ,使用activiti实现业务流程的管理。 系统模块(已完成) 请假模块 (已完成) 演示环境账号密码: 账号 密码 权限 ...
【标题】"基于Spring MyBatis和EasyUI的权限管理Demo"揭示了这是一个采用主流Java技术栈构建的权限管理系统...通过练习这个Demo,开发者可以提升自己的Java Web开发技能,并为后续更复杂的系统集成和权限设计打下基础。
9.5.3 权限的类型和级别 9.5.4 REVOKE命令 9.5.5 使用GRANT和REVOKE的例子 9.6 创建一个Web用户 9.7 使用正确的数据库 9.8 创建数据库表 9.8.1 理解其他关键字的意思 9.8.2 理解列的类型 9.8.3 用SHOW和DESCRIBE来...