今天刚学习了通过自定义注解+拦截器实现权限控制,自己花了点时间整理,发到网站同网友交流分享。
一、定义一个自定义注解类
- import java.lang.annotation.Retention;
- import java.lang.annotation.RetentionPolicy;
- /**
- * 自定义注解
- * @author grace
- *
- */
- @Retention(RetentionPolicy.RUNTIME)
- public @interface Limit{
- String module(); //模块名称
- String privilege(); //操作名称
- }
二、建好所需要的表
- #权限组表
- CREATE TABLE `sys_role` (
- `id` varchar(36), #编号
- `remark` TEXT, #备注
- `name` VARCHAR(100) DEFAULT NULL, #名称
- PRIMARY KEY (`id`)
- )
- #操作表
- CREATE TABLE sys_popedom
- (
- popedomModule VARCHAR(30), #模块名称
- popedomPrivilege VARCHAR(30), #操作名称
- sort INTEGER(11), #排序
- title VARCHAR(200), #提示
- popedomName VARCHAR(200), #标题
- remark TEXT, #说明
- PRIMARY KEY(popedomModule,popedomPrivilege)
- )
- #操作权限表
- CREATE TABLE sys_popedom_privilege
- (
- roleId VARCHAR(36), #权限组编号
- popedomModule VARCHAR(30), #模块名称
- popedomPrivilege VARCHAR(30), #操作名称
- PRIMARY KEY(roleId,popedomModule,popedomPrivilege)
- )
解释下以上3个表的作用:
1.权限组表:定义了一个权限,权限有id,name和remark。
2.操作表:该表相当于是你这个项目里所有的权限。popedomModule代表一个大的功能模块,popedomPrivilege代表一个模块下的具体操作:常见的有增删改查,可参考下图理解。
3.操作权限表:该表是权限组所对应的模块和操作。例子:如下图的roleId为8af0897545e4c91b0145e4cd385d0002,在权限组表中对应的是系统管理员权限组(见上上图),该权限组拥有的模块和操作名称在下图第二三列,可对应上图知道功能。说明:系统管理员权限组在当前系统中,只拥有下图所示的模块为city和code的所有操作权限,没有模块为company下的任何操作权限。通过将用户分配到不同的权限组,和设置权限组的拥有的模块和操作,就可以实现权限控制。
三、定义上面三个表所对应的类和*.hbm.xml(如果需要)
权限组表:
- /*
- * SysRole:权限组表
- */
- @SuppressWarnings("serial")
- public class SysRole implements java.io.Serializable {
- private String id;
- private String name;
- private String remark;
- public String getId() {
- return id;
- }
- public void setId(String id) {
- this.id = id;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getRemark() {
- return remark;
- }
- public void setRemark(String remark) {
- this.remark = remark;
- }
- }
注:因为在操作表(sys_popedom)和权限操作表(sys_popedom_privilege)中都为联合主键。因此在这里,我对这两个类都使用:新建一个类用来存放联合主键。
操作表:
- /*
- * 操作表
- */
- @SuppressWarnings("serial")
- public class SysPopedom implements java.io.Serializable{
- /*
- * CREATE TABLE sys_popedom
- (
- popedomModule VARCHAR(30), #模块名称
- popedomPrivilege VARCHAR(30), #操作名称
- sort INTEGER(11), #排序
- title VARCHAR(200), #提示
- popedomName VARCHAR(200), #标题
- remark TEXT, #说明
- PRIMARY KEY(popedomModule,popedomPrivilege)
- )
- */
- private SysPopedomId id;//主键 OID
- private Integer sort;
- private String title;
- private String popedomName;
- private String remark;
- public SysPopedomId getId() {
- return id;
- }
- public void setId(SysPopedomId id) {
- this.id = id;
- }
- public Integer getSort() {
- return sort;
- }
- public void setSort(Integer sort) {
- this.sort = sort;
- }
- public String getTitle() {
- return title;
- }
- public void setTitle(String title) {
- this.title = title;
- }
- public String getPopedomName() {
- return popedomName;
- }
- public void setPopedomName(String popedomName) {
- this.popedomName = popedomName;
- }
- public String getRemark() {
- return remark;
- }
- public void setRemark(String remark) {
- this.remark = remark;
- }
- }
- /**
- * 操作表中的联合主键类
- * @author grace
- *
- */
- @SuppressWarnings("serial")
- public class SysPopedomId implements java.io.Serializable {
- private String popedomModule;
- private String popedomPrivilege;
- public String getPopedomModule() {
- return popedomModule;
- }
- public void setPopedomModule(String popedomModule) {
- this.popedomModule = popedomModule;
- }
- public String getPopedomPrivilege() {
- return popedomPrivilege;
- }
- public void setPopedomPrivilege(String popedomPrivilege) {
- this.popedomPrivilege = popedomPrivilege;
- }
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result
- + ((popedomModule == null) ? 0 : popedomModule.hashCode());
- result = prime
- * result
- + ((popedomPrivilege == null) ? 0 : popedomPrivilege.hashCode());
- return result;
- }
- @Override
- public boolean equals(Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (getClass() != obj.getClass())
- return false;
- final SysPopedomId other = (SysPopedomId) obj;
- if (popedomModule == null) {
- if (other.popedomModule != null)
- return false;
- } else if (!popedomModule.equals(other.popedomModule))
- return false;
- if (popedomPrivilege == null) {
- if (other.popedomPrivilege != null)
- return false;
- } else if (!popedomPrivilege.equals(other.popedomPrivilege))
- return false;
- return true;
- }
- }
操作权限表:
- /**
- * 操作权限表
- * @author grace
- *
- */
- @SuppressWarnings("serial")
- public class SysPopedomPrivilege implements java.io.Serializable {
- /*
- * CREATE TABLE sys_popedom_privilege
- * (
- * roleId VARCHAR(36), #权限组编号
- * popedomModule VARCHAR(30), #模块名称
- * popedomPrivilege VARCHAR(30), #操作名称
- * PRIMARY KEY(roleId,popedomModule,popedomPrivilege)
- * )
- */
- private SysPopedomPrivilegeId id;
- public SysPopedomPrivilegeId getId() {
- return id;
- }
- public void setId(SysPopedomPrivilegeId id) {
- this.id = id;
- }
- }
- /**
- * 操作权限表的联合主键类
- * @author grace
- *
- */
- @SuppressWarnings("serial")
- public class SysPopedomPrivilegeId implements java.io.Serializable {
- private String roleId;
- private String popedomModule;
- private String popedomPrivilege;
- public String getRoleId() {
- return roleId;
- }
- public void setRoleId(String roleId) {
- this.roleId = roleId;
- }
- public String getPopedomModule() {
- return popedomModule;
- }
- public void setPopedomModule(String popedomModule) {
- this.popedomModule = popedomModule;
- }
- public String getPopedomPrivilege() {
- return popedomPrivilege;
- }
- public void setPopedomPrivilege(String popedomPrivilege) {
- this.popedomPrivilege = popedomPrivilege;
- }
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result
- + ((popedomModule == null) ? 0 : popedomModule.hashCode());
- result = prime
- * result
- + ((popedomPrivilege == null) ? 0 : popedomPrivilege.hashCode());
- result = prime * result + ((roleId == null) ? 0 : roleId.hashCode());
- return result;
- }
- @Override
- public boolean equals(Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (getClass() != obj.getClass())
- return false;
- final SysPopedomPrivilegeId other = (SysPopedomPrivilegeId) obj;
- if (popedomModule == null) {
- if (other.popedomModule != null)
- return false;
- } else if (!popedomModule.equals(other.popedomModule))
- return false;
- if (popedomPrivilege == null) {
- if (other.popedomPrivilege != null)
- return false;
- } else if (!popedomPrivilege.equals(other.popedomPrivilege))
- return false;
- if (roleId == null) {
- if (other.roleId != null)
- return false;
- } else if (!roleId.equals(other.roleId))
- return false;
- return true;
- }
- }
如果需要*.hbm.xml则进行配置。
四、写自定义拦截器
- import javax.servlet.http.HttpServletRequest;
- import org.apache.struts2.ServletActionContext;
- import com.opensymphony.xwork2.ActionInvocation;
- import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
- /**
- * 自定义拦截器
- * @author grace
- *
- */
- @SuppressWarnings("serial")
- public class LimitInterceptor extends MethodFilterInterceptor{
- public String doIntercept(ActionInvocation invocation) throws Exception {
- //获取请求的action对象
- Object action=invocation.getAction();
- //获取请求的方法的名称
- String methodName=invocation.getProxy().getMethod();
- //获取action中的方法的封装类(action中的方法没有参数)
- Method method=action.getClass().getMethod(methodName, null);
- //获取request对象
- HttpServletRequest request=ServletActionContext.getRequest();
- //检查注解
- boolean flag=isCheckLimit(request,method);
- if(!flag){
- //没有权限,通过struts2转到事先定义好的页面
- return "popmsg_popedom";
- }
- //有权限,可以调用action中的方法
- String returnvalue=invocation.invoke();
- return returnvalue;
- }
- public boolean isCheckLimit(HttpServletRequest request, Method method) {
- if(method==null){
- return false;
- }
- //获取当前的登陆用户
- SysUser sysUser=SessionUtils.getSysUserFormSession(request);
- if(sysUser==null){
- return false;
- }
- //如果用户的权限组为空
- if(sysUser.getSysRole()==null){
- return false;
- }
- //获取当前登陆用户的权限组id
- String roleId=sysUser.getSysRole().getId();
- //处理注解
- /*
- * @Limit(module="group",privilege="list")
- public String list(){
- ....
- }
- */
- //判断用户请求的method上面是否存在注解
- boolean isAnnotationPresent= method.isAnnotationPresent(Limit.class);
- //不存在注解
- if(!isAnnotationPresent){
- return false;
- }
- //存在注解,拿到由Limit类写的注解
- Limit limit=method.getAnnotation(Limit.class);
- //获取注解上的值
- String module=limit.module(); //模块名称
- String privilege=limit.privilege(); //操作名称
- /**
- * 如果登陆用户的权限组id+注解上的@Limit(module="group",privilege="list")
- * * 在sys_popedom_privilege表中存在 flag=true;
- * * 在sys_popedom_privilege表中不存在 flag=false;
- */
- boolean flag=false;
- //通过自己封装的方法拿到操作权限的业务层对象
- ISysPopedomPrivilegeService sysPopedomPrivilegeService=
- (ISysPopedomPrivilegeService)ServiceProvinder.getService(ISysPopedomPrivilegeService.SERVICE_NAME);
- //查询sys_popedom_privilege表中的所有的数据
- //因为后面用到二级缓存,因此这里直接查询出所有的操作权限,而不是通过登陆用户的权限组来查询
- List<SysPopedomPrivilege> list=sysPopedomPrivilegeService.findAllSysPopedomPrivileges();
- if(list!=null&&list.size()>0){
- for(int i=0;i<list.size();i++){
- SysPopedomPrivilege s=list.get(i);
- if(s!=null){
- //判断登陆用户是否拥有该方法的权限:如果登陆用户的roleId和登陆用户访问的方法
- //的注释中的module和privilege(例如@Limit(module="group",privilege="list")),这三个字段
- //在sys_popedom_privilege表中有记录与之对应,则代表该用户拥有权限访问此方法
- if(roleId.equals(s.getId().getRoleId())&&module.equals(s.getId().getPopedomModule())
- &&privilege.equals(s.getId().getPopedomPrivilege())){
- flag=true;
- break;
- }
- }
- }
- }
- return flag;
- }
- }
五、在struts.xml中配置自定义拦截器和没有权限时访问的页面。
- <interceptors>
- <!-- 声明拦截器 -->
- <interceptor name="limitInterceptor" class="cn.grace.interceptor.LimitInterceptor"></interceptor>
- <interceptor-stack name="limitStack">
- <interceptor-ref name="defaultStack" />
- <interceptor-ref name="limitInterceptor">
- <!-- 配置不被拦截的方法 -->
- <param name="excludeMethods">isLogin,logout,top,left</param>
- </interceptor-ref>
- </interceptor-stack>
- </interceptors>
- <!-- struts2运行时,执行的拦截器栈 -->
- <default-interceptor-ref name="limitStack" />
- <global-results>
- <!-- 转发到没有权限的页面 -->
- <result name="popmsg_popedom">/WEB-INF/page/popmsg_popedom.jsp</result>
- </global-results>
六、通过在Action的方法中进行注释,实现权限控制。
- import cn.grace.annotation.Limit;
- public class testUserAction {
- /** 用户添加页面 */
- @Limit(module="user",privilege="add")
- public String add(){
- return "add";
- }
- /** 用户添加 **/
- @Limit(module="user",privilege="save")
- public String save(){
- return "save";
- }
- /** 用户删除 **/
- @Limit(module="user",privilege="delete")
- public String delete(){
- return "delete";
- }
- /** 用户修改页面 **/
- @Limit(module="user",privilege="edit")
- public String edit() {
- return "edit";
- }
- /** 用户修改 **/
- @Limit(module="user",privilege="update")
- public String update() {
- return "update";
- }
- /** 用户列表 (查询) */
- @Limit(module="user",privilege="list")
- public String list() {
- return "list";
- }
- }
七、整个权限控制的功能实现概要为:
例子:3个不同权限的用户
1.系统管理的权限id(roleId)为:8af0897545e4c91b0145e4cd385d0002;而在sys_popedom_privilege表中,roleId为:8af0897545e4c91b0145e4cd385d0002,拥有所有模块和操作,则系统管理员拥有所有模块的所有操作权限。
2.部门经理的权限id(roleId)为:8af09d7845fe6ef90145fe70a0a80001;而在sys_popedom_privilege表中,roleId为:8af09d7845fe6ef90145fe70a0a80001,拥有部门模块的所有操作(9个),则部门经理拥有部门模块的所有9个操作权限,但没有其他(例如city和code模块)模块的操作权限。
3.小明的权限id(roleId)为:8af0897545e4c91b0145e4cd65b30003;而在sys_popedom_privilege表中,roleId为:8af0897545e4c91b0145e4cd65b30003,仅拥有部门模块的部分操作(比部门经理比少了list和edit操作),则小明拥有部门模块下的部分操作权限。如下图,其中roleId为8af0897545e4c91b0145e4cd65b30003对应的模块和操作只有下图前7行。