有了上此讲座的基础,我想理解我们这个功能应该就很容易了。刚刚我们经理问我有用户希望控制web登陆用户的权限,那么我们正好利用这个讲座来看看如何实现这个功能。我们新建一个类,functionality当然要实现GISFunctionality接口了:
<?xml:namespace prefix = o ns = "urn:schemas-microsoft-comfficeffice" />
public class SecurityCheckFunctionality implements GISFunctionality {
private AGSMapResource resource;
public void initFunctionality(GISResource resource) { //empty }
public void destroyFunctionality() { //empty }
public GISResource getResource() { //empty }
}
我们在这里放了一个AGSMapResource类型的变量,因为我们需要对Resource进行很多操作,我们来看一下:
public void initFunctionality(GISResource resource) {
this.resource = (AGSMapResource)resource; //得到资源
//查看用户是否属于"petroEmployee" 角色
if(!WebUtil.getExternalContext().isUserInRole("pretroEmployee")){
//从Resource中得到MapFunctionality
AGSMapFunctionality mapFunc = (AGSMapFunctionality)resource.getFunctionality("map");
//得到对 MapServerInfo的引用
MapServerInfo serverInfo = mapFunc.getMapServerInfo();
//得到 "Pipeline_Network" 层
MapLayerInfo pipelineLayerInfo = AGSUtil.getLayerInfo("PipeLine_Network",layerInfos);
if(pipelineLayerInfo==null)
return; //层不存在,return.
//从TOC中移除
MapLayerInfo[] newLayerInfos = removeLayer(pipelineLayerInfo,layerInfos);
serverInfo.setMapLayerInfos(newLayerInfos);
//从MAP中移除
LayerDescription[] layerDescriptions =serverInfo.getDefaultMapDescription().getLayerDescriptions();
//新建一个层描述,替换原来的层描述
LayerDescription[] newLayerDescriptions = new LayerDescription[newLayerInfos.length];
for(int i=0;i<newLayerInfos.length;i++){
newLayerDescriptions=AGSUtil.getLayerDescription(newLayerInfos.getLayerID(),layerDescriptions);
5 serverInfo.getDefaultMapDescription().setLayerDescriptions(newLayerDescriptions);
}
}
上面的代码中用removeLayer(pipelineLayerInfo,layerInfos);函数移除了要移除的层,然后更新了TOC和MAP,我们来看看这个函数怎么来写:
//Logic to remove a layer and all its descendants
private MapLayerInfo[] removeLayer(MapLayerInfo unwantedLayerInfo, MapLayerInfo[] oldLayerInfos) {
//新建一个MapLayerInfo
MapLayerInfo[] newLayerInfos = new MapLayerInfo[oldLayerInfos.length-1];
ArrayList descendantLayers = new ArrayList();
for(int i=0,j=0;i<oldLayerInfos.length;i++){
if(oldLayerInfos.getLayerID()!=unwantedLayerInfo.getLayerID())
newLayerInfos[j++] = oldLayerInfos;
if(oldLayerInfos.getParentLayerID()==unwantedLayerInfo.getLayerID())
descendantLayers.add(oldLayerInfos);
}
for(int i=0;i<descendantLayers.size();i++){
newLayerInfos = removeLayer((MapLayerInfo)descendantLayers.get(i),newLayerInfos);
}
return newLayerInfos;
}
我们注意到这是一个递归函数,用于把该层下面所有的其它附属层都删除:
这个functionality写完了,我们来看看如何部署,部署的时候,先把它作为一个Managed Bean部署,用下面可代码即可,可以在faces-config.xml文件里面,也可以在ags-functionality.xml里面:
<managed-bean>
<managed-bean-name>securitycheck</managed-bean-name>
<managed-bean-class>com.mypackage.SecurityCheckFunctionality</managed-bean-class>
<managed-bean-scope>none</managed-bean-scope>
</managed-bean>
将它作为一个managedBean部署后,下面就把它部署到resource中,注意部署的时候,要将其部署到map之后,toc之前,因为ADF初始化是按顺序初始化,我们的权限控制需要从Map中读出层的信息,然后修改MapDesc,从而影响TOC的信息,所以,进行如下的部署配置:
<managed-bean>
<managed-bean-name>ags1</managed-bean-name>
<managed-bean-class>
com.esri.adf.web.ags.data.AGSLocalMapResource
</managed-bean-class>
<managed-bean-scope>none</managed-bean-scope>
...
<managed-property>
<property-name>functionalities</property-name>
<map-entries>
<map-entry>
<key>map</key>
<value>#{agsMap}</value>
</map-entry>
<map-entry>
<key>query</key>
<value>#{agsQuery}</value>
</map-entry>
<map-entry>
<key>tile</key>
<value>#{agsTile}</value>
</map-entry>
<map-entry>
<key>overview</key>
<value>#{agsOverview}</value>
</map-entry>
<map-entry>
<key>pipeline_security_check</key>
<value>#{securitycheck}</value>
</map-entry>
<map-entry>
<key>toc</key>
<value>#{agsToc}</value>
</map-entry>
</map-entries>
</managed-property>
</managed-bean>
OK,这个安全控制的functionality已经完成了。但是我们要对整个WebApplication加上安全控制,需要在web.xml做修改,添加如下的配置:
<login-config>
<auth-method>DIGEST</auth-method>
<realm-name>My_WebApplication</realm-name>
</login-config>
//声明两个组用户
<security-role>
<role-name>petroEmployee</role-name>
</security-role>
<security-role>
<role-name>stateEmployee</role-name>
</security-role>
//声明什么资源将收到安全控制,这里我们把整个目录都控制,当然你也可以控制胆敢目录
<security-constraint>
<web-resource-collection>
<url-pattern>*<url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>petroEmployee</role-name>
<role-name>stateEmployee<role-name>
</auth-constraint>
</security-constraint>
这两个组在什么地方定义呢?如果是Tomcat,我们可以在$TOMCAT_HOME/conf/tomcat-users.xml中定义,定义如下:
<tomcat-users> ...
<user name="joe" password="joe" roles="petroEmployee">
<user name="daisy" password="daisy" roles="stateEmployee">
...
</tomcat-users>
这样我们就控制了整个Web Application,并且对于不同的用户组,赋予了不同的层的查看权限。每次用户访问这个网站的时候,都会被提示要求输入用户名和密码,按照我们在Tomcat-users里面的定义进行输入即可。
还有用户会问道,如果我希望对属性字段的编辑进行控制怎么办;事实上原理是类似的,你让用户修改属性字段时,肯定要传输一个字段列表,你可以根据不同的用户组,对这个字段列表进行控制。
另外,这里我们用了WEB容器的用户和权限进行控制,事实上你不必依赖于Web容器,你可以在数据库中存放你自己定义的用户名和组,进行控制。
权限控制简单的讲就是这样子,.net里面也类似,有机会的话,我会写一个.net版本的给大家看看。
注:本讲座内容参考了并翻译了ESRI的JAVA帮助的部分内容。