做授权控制时不仅仅要用户无法访问的连接不能看到,还要阻止用户通过其他手段得到连接地址而直接调用连接。因此授权控制时还必须防止用户执行jsp、servlet、以及WebService等等所有需要授权验证的服务。
为了做到这一点就必须在用户的入口处做授权校验,如jsp、servlet(struts的Action)等等(授权到底放在何处校验合适,web接口层还是业务的facade层?)。
实现后实现的范例代码:
@Authorizations(authorizations = {
@Authorization(rights = { "AccountMatchingRuler" }, test = "${param.rulerType=='AccountMatchingRuler'}"),
@Authorization(rights = { "IpMatchingRuler","Edit" }, test = "${param.rulerType=='IpMatchingRuler'}",type=AuthorizationElement.anyOne) })
public ActionForward doExecute(ActionMapping mapping, ActionForm form,HttpServletRequest request, HttpServletResponse response)
上面的意思是如果el表达式${param.rulerType=='AccountMatchingRuler'}判断为真怎校验当前用户是否有权限执行AccountMatchingRuler
如果${param.rulerType=='IpMatchingRuler'}为真,则当前用户必须具有执行IpMatchingRuler或者Edit的权限,其中之所有是具有其中一个即可执行,因为type
配置的是AuthorizationElement.anyOne,其意思指"任意一个",还有其他规则:all指必须全部具有;notAnyOne指不能包含其中任何一个。
只要任意一个Authorization执行校验成功则授权通过。授权通过则可以执行该方法。
在JSP中使用标签,范例代码如下:
确定该JSP能否执行
<authorization:authorizations>
<authorization:authorization rights="businessOperation"/>
</authorization:authorizations>
确定标签体中的内容是否显示(其实质是标签体是否执行,Skip_body还是evel_body)
<authorization:authorizationShow rights="addRole">
<div name="item"><html:link action="/addRolePre" target="content" styleClass="menu_li" οnclick="clickObject(${pageScope.showObjNum-1},${pageScope.itemNum})">添加岗位</html:link></div>
<c:set var="itemNum" value="${pageScope.itemNum+1}" scope="page"/>
</authorization:Show>
其配置和上面类似。
判断能否执行的核心代码如下:
public static boolean authorization(Class _class, String methodName,
Class[] paramters, String[] rightsForOperator)
throws NoSuchMethodException {
// 得到事件函数
Method eventMethod = _class.getMethod(event, paramters);
Authorization annotation = eventMethod
.getAnnotation(Authorization.class);
return authorization(annotation, rightsForOperator);
}
public static boolean authorization(Authorization annotation,
String[] rightsForOperator) {
if (annotation != null) {
String[] rights = annotation.rights();
AuthorizationElement type = annotation.type();
return authorization(rights, type, rightsForOperator);
}
return true;
}
public static boolean authorization(String[] rightRequired,
AuthorizationElement type, String[] rightsForOperator) {
if (rightRequired == null || type == null || rightsForOperator == null) {
return false;
}
if (logger.isDebugEnabled()) {
StringBuffer buffer = new StringBuffer();
buffer.append("rightRequired:");
for (String a : rightRequired) {
buffer.append(a).append(",");
}
buffer.append("/ttype:").append(type);
for (String a : rightsForOperator) {
buffer.append(a).append(",");
}
logger.debug(buffer);
}
List<String> roleNamesList = Arrays.asList(rightsForOperator);
if (type == AuthorizationElement.all) {
// 当前拥有的角色不存在任何一个则失败
for (String s : rightRequired) {
if (!roleNamesList.contains(s)) {
return false;
}
}
}
if (type == AuthorizationElement.anyOne) {
for (String s : rightRequired) {
if (roleNamesList.contains(s)) {
return true;
}
}
return false;
}
if (type == AuthorizationElement.notAnyOne) {
// 当前拥有的角色是列表中的任何一个
for (String s : rightRequired) {
if (roleNamesList.contains(s)) {
return false;
}
}
}
return true;
}
struts的Action,业务中的Action继承该BaseAction即可获得授权控制
public abstract class BaseAction extends Action {
private Authorizations authorizationsAnnotation;
private Authorization authorizationAnnotation;
private IRightDiscover rightDiscover = DefaultRightDiscover.getInstance();
protected BaseAction() {
Method doExecuteMethod = null;
try {
// 得到方法
doExecuteMethod = this.getClass()
.getMethod(
"doExecute",
new Class[] { ActionMapping.class,
ActionForm.class, HttpServletRequest.class,
HttpServletResponse.class });
// 得到AuthorizationsAnnotation
this.authorizationsAnnotation = doExecuteMethod
.getAnnotation(Authorizations.class);
this.authorizationAnnotation = doExecuteMethod
.getAnnotation(Authorization.class);
} catch (SecurityException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
@Override
public final ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
// 如果该方法没有配置Authorizations annotation,则认为不验证,否则则根据配置验证
JspFactory jspxFactory = JspFactory.getDefaultFactory();
PageContext pageContext = jspxFactory.getPageContext(getServlet(),
request, response, null, true, 8192, true);
if (authorizationsAnnotation != null) {
// 得到当前操作员所拥有的所有权限
String[] currentRights = rightDiscover.getRights(request);
if (currentRights == null) {
currentRights = new String[] {};
}
// 得到所配置的所有Authorization annotation
Authorization[] a = authorizationsAnnotation.authorizations();
for (int i = 0; i < a.length; i++) {
// 使用el确定是执行哪一个Authorization
if (((Boolean) pageContext.getExpressionEvaluator().evaluate(
a[i].test(), Boolean.class,
pageContext.getVariableResolver(), null))
.booleanValue()) {
// 验证权限
if (AuthorizationUtil.authorization(a[i], currentRights)) {
return doExecute(mapping, form, request, response);
} else {
throw new AuthorizationException(this.getClass()
.getName());
}
}
}
}
if (authorizationAnnotation != null) {
// 得到当前操作员所拥有的所有权限
String[] currentRights = rightDiscover.getRights(request);
if (currentRights == null) {
currentRights = new String[] {};
}
if (((Boolean) pageContext.getExpressionEvaluator().evaluate(
authorizationAnnotation.test(), Boolean.class,
pageContext.getVariableResolver(), null)).booleanValue()) {
// 验证权限
if (AuthorizationUtil.authorization(authorizationAnnotation,
currentRights)) {
return doExecute(mapping, form, request, response);
} else {
throw new AuthorizationException(this.getClass().getName());
}
}
}
// 如果没有配置Authorizations annotation或者没有找到应该执行哪一个Authorization
// annotation则表示通过授权
return doExecute(mapping, form, request, response);
}
@Override
public final ActionForward execute(ActionMapping arg0, ActionForm arg1,
ServletRequest arg2, ServletResponse arg3) throws Exception {
return super.execute(arg0, arg1, arg2, arg3);
}
public abstract ActionForward doExecute(ActionMapping mapping,
ActionForm form, HttpServletRequest request,
HttpServletResponse response) throws Exception;
public void setRightDiscover(IRightDiscover rightDiscover) {
this.rightDiscover = rightDiscover;
}
}
标签的实现代码相对要简单得多
下次要介绍的是使用Annotation实现DAO层的无代码编程:类似于jdbc4.0内的模式