基于Struts2、Annotation的细粒度权限管理

时间:2021-09-05 16:23:58
 

本文的目的是实现方法级的细粒度权限管理,通过Struts2 拦截器和Java的Annotation实现,具体实现方法如下:

1.数据表设计,并将实体Bean映射到数据库,本系统设计了权限组和具体权限表,由于两个表之间属于多对多关联,所以另有一个主键关联表。

权限组对应的实体Bean如下:

 

@Entity
public class PrivilegeGroup {
private String groupid;
private String name;
private Set<SystemPrivilege> privileges = new HashSet<SystemPrivilege>();
private Set<Employee> employees = new HashSet<Employee>();

public PrivilegeGroup(){}

public PrivilegeGroup(String groupid) {
this.groupid = groupid;
}
@ManyToMany(mappedBy="groups", cascade=CascadeType.REFRESH)
public Set<Employee> getEmployees() {
return employees;
}
public void setEmployees(Set<Employee> employees) {
this.employees = employees;
}
@Id @Column(length=36)
public String getGroupid() {
return groupid;
}
public void setGroupid(String groupid) {
this.groupid = groupid;
}
@Column(length=20,nullable=false)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@ManyToMany(cascade=CascadeType.REFRESH,fetch=FetchType.EAGER)
@JoinTable(name="ps", inverseJoinColumns={@JoinColumn(name="module", referencedColumnName="module"),
@JoinColumn(name="privilege", referencedColumnName="privilege")}
,joinColumns=@JoinColumn(name="group_id"))
public Set<SystemPrivilege> getPrivileges() {
return privileges;
}
public void setPrivileges(Set<SystemPrivilege> privileges) {
this.privileges = privileges;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((groupid == null) ? 0 : groupid.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 PrivilegeGroup other = (PrivilegeGroup) obj;
if (groupid == null) {
if (other.groupid != null)
return false;
} else if (!groupid.equals(other.groupid))
return false;
return true;
}
}


具体权限实体Bean如下:

@Entity
public class SystemPrivilege {
private SystemPrivilegePK id;
/* 权限名称 */
private String name;
private Set<PrivilegeGroup> groups = new HashSet<PrivilegeGroup>();

@ManyToMany(cascade=CascadeType.REFRESH, mappedBy="privileges")
public Set<PrivilegeGroup> getGroups() {
return groups;
}
public void setGroups(Set<PrivilegeGroup> groups) {
this.groups = groups;
}

public SystemPrivilege(){}

public SystemPrivilege(String module, String privilege, String name) {
this.id = new SystemPrivilegePK(module, privilege);
this.name = name;
}

public SystemPrivilege(SystemPrivilegePK id) {
this.id = id;
}

@EmbeddedId
public SystemPrivilegePK getId() {
return id;
}
public void setId(SystemPrivilegePK id) {
this.id = id;
}
@Column(length=20,nullable=false)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.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 SystemPrivilege other = (SystemPrivilege) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}

}


主键关联实体Bean如下:

@Embeddable
public class SystemPrivilegePK implements Serializable{
private static final long serialVersionUID = -5226216765297631665L;
/* 模块名 */
private String module;
/* 权限值 */
private String privilege;

public SystemPrivilegePK(){}

public SystemPrivilegePK(String module, String privilege) {
this.module = module;
this.privilege = privilege;
}
@Column(length=20, name="module")
public String getModule() {
return module;
}
public void setModule(String module) {
this.module = module;
}
@Column(length=20, name="privilege")
public String getPrivilege() {
return privilege;
}
public void setPrivilege(String privilege) {
this.privilege = privilege;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((module == null) ? 0 : module.hashCode());
result = prime * result
+ ((privilege == null) ? 0 : privilege.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 SystemPrivilegePK other = (SystemPrivilegePK) obj;
if (module == null) {
if (other.module != null)
return false;
} else if (!module.equals(other.module))
return false;
if (privilege == null) {
if (other.privilege != null)
return false;
} else if (!privilege.equals(other.privilege))
return false;
return true;
}
}


Employee实体Bean如下:

@Entity
public class Employee {
/* 主键,20位*/
private String username;
/* 20位, 不能为null */
private String password;
/* 姓名 10位 不能为null */
private String realname;
/* 性别 不能为null */
private Gender gender;
/* 学历 10位 */
private String degree;
/* 身份证 必须提供 */
private IDCard idCard;
/* 毕业院校 20位 */
private String school;
/* 联系电话 20 */
private String phone;
/* 电子邮件 50 */
private String email;
/* 照片 41 */
private String imageName;
/* 员工在职状态 true为在职,false为离职 */
private Boolean visible = true;
private Department department;
/* 拥有的权限 */
private Set<PrivilegeGroup> groups = new HashSet<PrivilegeGroup>();

@ManyToMany(cascade=CascadeType.REFRESH,fetch=FetchType.EAGER)
@JoinTable(name="employee_role",joinColumns=@JoinColumn(name="username"),
inverseJoinColumns=@JoinColumn(name="groupid"))
public Set<PrivilegeGroup> getGroups() {
return groups;
}

public void setGroups(Set<PrivilegeGroup> groups) {
this.groups = groups;
}
/**
* 添加权限组
* @param group
*/
public void addPrivilegeGroup(PrivilegeGroup group){
this.groups.add(group);
}

public Employee(){}

public Employee(String username) {
this.username = username;
}

@Transient
public String getImagePath(){
if(username != null && imageName != null)
return "/images/employee/" + username+"/" + imageName;
return null;
}

@Id @Column(length=20)
public String getUsername() {
return username;
}

public void setUsername(String username) {
this.username = username;
}
@Column(length=20,nullable=false)
public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}
@Column(length=10,nullable=false)
public String getRealname() {
return realname;
}

public void setRealname(String realname) {
this.realname = realname;
}
@Enumerated(EnumType.STRING) @Column(length=5,nullable=false)
public Gender getGender() {
return gender;
}

public void setGender(Gender gender) {
this.gender = gender;
}
@Column(length=10)
public String getDegree() {
return degree;
}

public void setDegree(String degree) {
this.degree = degree;
}
@OneToOne(cascade=CascadeType.ALL,optional=false)
@JoinColumn(name="card_id")
public IDCard getIdCard() {
return idCard;
}

public void setIdCard(IDCard idCard) {
this.idCard = idCard;
}
@Column(length=20)
public String getSchool() {
return school;
}

public void setSchool(String school) {
this.school = school;
}
@Column(length=20)
public String getPhone() {
return phone;
}

public void setPhone(String phone) {
this.phone = phone;
}
@Column(length=50)
public String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email;
}
@Column(length=41)
public String getImageName() {
return imageName;
}

public void setImageName(String imageName) {
this.imageName = imageName;
}
@Column(nullable=false)
public Boolean getVisible() {
return visible;
}

public void setVisible(Boolean visible) {
this.visible = visible;
}

@ManyToOne(cascade=CascadeType.REFRESH)
@JoinColumn(name="department_id")
public Department getDepartment() {
return department;
}

public void setDepartment(Department department) {
this.department = department;
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((username == null) ? 0 : username.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 Employee other = (Employee) obj;
if (username == null) {
if (other.username != null)
return false;
} else if (!username.equals(other.username))
return false;
return true;
}
}


2.管理员在系统后台管理系统中某个Employee设定所属权限组,该Employee就拥有了该权限组所定义的所以权限。

实现方法级的权限拦截,需要自定义Annotation,本系统中定义了一个Permission注解,具体如下:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Permission {
/* 模块名 */
String module();
/* 权限值 */
String privilege();
}


3.定义权限注解后,即可将其添加到Action的对应方法上:

@Permission(module="privilegeGroup", privilege="delete")
public String delete(){
groupService.delete((Serializable)groupDTO.getGroupid());
request.setAttribute("message", "删除权限组成功");
request.setAttribute("urladdress", SiteUrl.readUrl("control.privilegegroup.list"));
return "message";
}


4.然后需要自定义拦截器,对Action进行拦截,在拦截器中对用户是否有权限执行Action的对应方法进行判断:

public class PermissionInterceptor extends AbstractInterceptor {
private static final long serialVersionUID = -1424613722721479288L;

@Override
public String intercept(ActionInvocation invocation) throws Exception {
HttpServletRequest request = (HttpServletRequest)invocation.getInvocationContext().get(StrutsStatics.HTTP_REQUEST);
Employee employee = WebUtil.getEmployee(request);
if(employee != null && validate(employee,invocation)){
return invocation.invoke();
}
request.setAttribute("message", "你没有权限执行该操作");
request.setAttribute("urladdress", SiteUrl.readUrl("control.center.right"));

return "message";
}
public boolean validate(Employee employee,ActionInvocation invocation){
String methodName = "execute";
Method currentMethod = null;
methodName = invocation.getProxy().getMethod();
try{
currentMethod = invocation.getProxy().getAction().getClass().getMethod(methodName, new Class[]{});
}catch(Exception e){
e.printStackTrace();
}
if(currentMethod != null && currentMethod.isAnnotationPresent(Permission.class)){
Permission permission = currentMethod.getAnnotation(Permission.class);
SystemPrivilege privilege = new SystemPrivilege(new SystemPrivilegePK(permission.module(),
permission.privilege()));
for(PrivilegeGroup group : employee.getGroups()){
if(group.getPrivileges().contains(privilege))
return true;
}
return false;
}
return true;
}

}


5.在struts2配置文件中注册权限拦截器,并使用其对Action进行拦截:

<interceptors>
<interceptor name="permissionInterceptor" class="com.hnust.web.interceptor.PermissionInterceptor"/>
<interceptor-stack name="myInterceptor">
<interceptor-ref name="permissionInterceptor"></interceptor-ref>
<interceptor-ref name="defaultStack"></interceptor-ref>
</interceptor-stack>
</interceptors>


 

<package name="privilegegroup" namespace="/control/privilegegroup" extends="default">
<default-interceptor-ref name="myInterceptor"></default-interceptor-ref>
<action name="list" class="com.hnust.web.action.privilege.PrivilegeGroupListAction">
<result name="list">/WEB-INF/page/department/privilegegrouplist.jsp</result>
</action>
<action name="manage" class="com.hnust.web.action.privilege.PrivilegeGroupManageAction">
<result name="add">/WEB-INF/page/department/addprivilegegroup.jsp</result>
<result name="edit">/WEB-INF/page/department/editprivilegegroup.jsp</result>
</action>
</package>