最近在做学习S2SH时,有一个模块式权限控制,就是对用户的操作存在权限分级操作,即不是所有的用户都可以访问全部数据。下面说一下这次我们的做法。
1.所谓权限控制,就是对URL地址的控制,用户角色中不存在该权限,那么该url地址对用户是不起反应的(用户点击无反应),最好是不可见的。整体的思路就是这样,通过对UI标签的控制而达到对权限的控制。
2.我们使用的是struts2中的a标签,而非使用简单的html中a标签。原因是在<s:a>标签的源码中存在doStartTag()和doEndTag()方法.假设存在以下标签:
<s:a action="user_delete.action?id=%{id}" onClick="return delConfirm()">删除</s:a>
那么在执行doStartTag()方法之后,标签会读到<s:a action="user_delete.action?id=%{id}" onClick="return delConfirm()">,并没有将标签信息读完! 在执行完doEndTag()方法之后,标签会将剩下的配置读完。所以要检查是否存在权限,需要在doEndTag()方法中增加自己的逻辑。
3.下面来简单介绍一下如下修改UI之<s:a>源码。在struts2-core源码包下找到META-INF文件夹(不出意外的话应该是最下面位置),打开里面的struts-tags.tld.通过搜索<name>a</name>找到标签中的对应的原始类org.apache.struts2.views.jsp.ui.AnchorTag,然后打开该源码(打不开也没关系,等会你拷我的源码就可以了。因为我装了GD-GUI插件,建议打不开jar文件的你也装一下).在你的项目src下新建一个org.apache.struts2.views.jsp.ui的包,在包内新建一个AnchorTag类(是的,与上面的类一模一样,原因很简单,jvm会优先加载src下的class文件,src下的class文件找不到就去外部jar包中查找),代码如下:
package org.apache.struts2.views.jsp.ui; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.jsp.JspException; import org.apache.struts2.components.Anchor; import org.apache.struts2.components.Component; import com.it.entity.User; import com.opensymphony.xwork2.util.ValueStack; public class AnchorTag extends AbstractClosingTag { private static final long serialVersionUID = -1034616578492431113L; protected String href; protected String includeParams; protected String scheme; protected String action; protected String namespace; protected String method; protected String encode; protected String includeContext; protected String escapeAmp; protected String portletMode; protected String windowState; protected String portletUrlType; protected String anchor; protected String forceAddSchemeHostAndPort; public Component getBean(ValueStack stack, HttpServletRequest req, HttpServletResponse res) { return new Anchor(stack, req, res); } /** * 自定义的代码 */ @Override public int doEndTag() throws JspException { User user = (User) pageContext.getSession().getAttribute("user"); <span style="white-space:pre"> </span>//user.hasThisURLPrivilege(String url)是配对自己是否用于权限 if(user != null && user.hasThisURLPrivilege(action)){ return super.doEndTag(); }else{ return EVAL_PAGE ; } } protected void populateParams() { super.populateParams(); Anchor tag = (Anchor) this.component; tag.setHref(this.href); tag.setIncludeParams(this.includeParams); tag.setScheme(this.scheme); tag.setValue(this.value); tag.setMethod(this.method); tag.setNamespace(this.namespace); tag.setAction(this.action); tag.setPortletMode(this.portletMode); tag.setPortletUrlType(this.portletUrlType); tag.setWindowState(this.windowState); tag.setAnchor(this.anchor); if (this.encode != null) { tag.setEncode(Boolean.valueOf(this.encode).booleanValue()); } if (this.includeContext != null) { tag.setIncludeContext(Boolean.valueOf(this.includeContext) .booleanValue()); } if (this.escapeAmp != null) { tag.setEscapeAmp(Boolean.valueOf(this.escapeAmp).booleanValue()); } if (this.forceAddSchemeHostAndPort != null) tag.setForceAddSchemeHostAndPort(Boolean.valueOf( this.forceAddSchemeHostAndPort).booleanValue()); } public void setHref(String href) { this.href = href; } public void setEncode(String encode) { this.encode = encode; } public void setIncludeContext(String includeContext) { this.includeContext = includeContext; } public void setEscapeAmp(String escapeAmp) { this.escapeAmp = escapeAmp; } public void setIncludeParams(String name) { this.includeParams = name; } public void setAction(String action) { this.action = action; } public void setNamespace(String namespace) { this.namespace = namespace; } public void setMethod(String method) { this.method = method; } public void setScheme(String scheme) { this.scheme = scheme; } public void setValue(String value) { this.value = value; } public void setPortletMode(String portletMode) { this.portletMode = portletMode; } public void setPortletUrlType(String portletUrlType) { this.portletUrlType = portletUrlType; } public void setWindowState(String windowState) { this.windowState = windowState; } public void setAnchor(String anchor) { this.anchor = anchor; } public void setForceAddSchemeHostAndPort(String forceAddSchemeHostAndPort) { this.forceAddSchemeHostAndPort = forceAddSchemeHostAndPort; } }
需要修改的方法就是在doTagEnd()中,存在于父类中。首先我们会获取该用户的信息,在User存在的情况下,我们进行判断,在用户拥有该权限时,执行
return super.doEndTag();
该方法的意思是:显示该超链接的信息,然后继续执行后面的代码。当用户不存在该权限时,执行
return EVAL_PAGE ;
该方法的意思是:不显示该超链接的信息(就是意味着该标签将不显示于JSP文件中了),然后继续执行后面的代码。
好了,我感觉我说清楚了,虽然这只是一个小知识,但是如果不使用的UI标签去判断是否存在权限,那么感觉代码不会像这样简洁了吧。。