<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
">
<description>apache shiro 配置</description>
<context:component-scan base-package="com.haier.uhome.hr91.util.shiro" />
<!-- 自定义shiro的realm数据库身份验证 -->
<bean id="jdbcAuthenticationRealm" class="com.haier.uhome.hr91.util.shiro.JdbcAuthenticationRealm" >
<property name="name" value="jdbcAuthentication" />
<property name="credentialsMatcher">
<bean class="com.haier.uhome.hr91.util.shiro.UhomeSecurityPasswd">
</bean>
</property>
<property name="defaultPermissionString" value="security:index,menu:list,info:list" />
</bean>
<bean id="customRememberMeManager" class="com.haier.uhome.hr91.util.shiro.CustomRememberMeManager"></bean>
<bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager"></bean>
<!-- 使用默认的WebSecurityManager -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<!-- realm认证和授权,从数据库读取资源 -->
<property name="realm" ref="jdbcAuthenticationRealm" />
<property name="rememberMeManager" ref="customRememberMeManager" />
<property name="sessionManager" ref="sessionManager" />
</bean>
<!-- 自定义对 shiro的连接约束,结合shiroSecurityFilter实现动态获取资源 -->
<bean id="chainDefinitionSectionMetaSource" class="com.haier.uhome.hr91.util.shiro.ChainDefinitionSectionMetaSource">
<!-- 默认的连接配置 -->
<property name="filterChainDefinitions">
<value>
/manager/login.do = captchaAuthc
/manager/logout.do = logout
/manager/css/** = anon
/manager/images/** = anon
/manager/js/** = anon
/webservice/VerificationCode = anon
/manager/index.html = perms[security:index]
/manager/changePassword = perms[security:change-password]
/manager/menu.do = perms[menu:list]
/manager/info.do = perms[info:list]
</value>
</property>
<property name="webmap">
<value>/WEB-INF/conf/webmap.xml</value>
</property>
</bean>
<!-- 将shiro与spring集合 -->
<bean id="captchaAuthenticationFilter" class="com.haier.uhome.hr91.util.shiro.CaptchaAuthenticationFilter">
<property name="usernameParam"><value>loginName</value></property>
<property name="passwordParam"><value>loginPwd</value></property>
<property name="captchaParam"><value>rand</value></property>
<property name="sessionCaptchaKeyAttribute"><value>repeatCode</value></property>
<property name="failureKeyAttribute"><value>errStr</value></property>
</bean>
<bean id="uhomeRoleFilter" class="com.haier.uhome.hr91.util.shiro.UhomeRolesAuthorizationFilter"></bean>
<bean id="logout" class="org.apache.shiro.web.filter.authc.LogoutFilter">
<property name="redirectUrl"><value>/manager/login.do</value></property>
</bean>
<bean id="shiroSecurityFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="filters">
<map>
<entry key="captchaAuthc" value-ref="captchaAuthenticationFilter" />
<entry key="uhomeRoles" value-ref="uhomeRoleFilter" />
</map>
</property>
<!-- shiro的核心安全接口 -->
<property name="securityManager" ref="securityManager" />
<property name="loginUrl" value="/manager/login.do" />
<property name="successUrl" value="/manager/index.html" />
<!-- shiro连接约束配置,在这里使用自定义的动态获取资源类 -->
<property name="filterChainDefinitionMap" ref="chainDefinitionSectionMetaSource" />
</bean>
<!-- shiro为集成spring -->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />
<!-- 启用shiro为spring配置的bean注释,只运行在lifecycleBeanProcessor之后 -->
<bean id="annotationProxy" class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor">
<property name="proxyTargetClass" value="true" />
</bean>
<!-- 启用shrio授权注解拦截方式 -->
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager" />
</bean>
</beans>
JdbcAuthenticationRealm.java
public class JdbcAuthenticationRealm extends AuthorizingRealm
{
@Autowired
AdminService adminService;
@Autowired
ManagerDAO managerDAO;
@Autowired
ManagerRoleService managerRoleService;
List<String> defaultPermission = new ArrayList<String>();
@Override
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken token) throws AuthenticationException
{
UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
String username = usernamePasswordToken.getUsername();
String tmpPassword = null;
if (username == null)
{
throw new AccountException("用户名不能为空");
}
Admin user = adminService.findByLoginName(username);
Manager manager = null;
CommonVariableModel model = new CommonVariableModel();
if (user == null)
{
manager = managerDAO.findByLoginName(username);
if (manager == null)
throw new UnknownAccountException("用户不存在");
else
{
tmpPassword = manager.getLoginPwd();
model.setManager(manager);
}
} else
{
tmpPassword = user.getPassword();
model.setUser(user);
}
return new SimpleAuthenticationInfo(model, tmpPassword, getName());
}
/**
*
* 当用户进行访问链接时的授权方法
*
*/
protected AuthorizationInfo doGetAuthorizationInfo(
PrincipalCollection principals)
{
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
CommonVariableModel model = (CommonVariableModel) principals
.getPrimaryPrincipal();
info.addStringPermissions(defaultPermission);
Manager manager = model.getManager();
Admin user = model.getUser();
if (manager != null)
{
info.addRole(manager.getRole());
} else if (user != null)
{
info.addRole(user.getRole());
}
info.addRole("zbx");
return info;
}
public void setDefaultPermissionString(String defaultPermissionString)
{
String[] perms = defaultPermissionString.split(",");
CollectionUtils.addAll(defaultPermission, perms);
}
}
CustomRememberMeManager
public class CustomRememberMeManager extends CookieRememberMeManager
{
/**
* 构造方法,不在这里对Cookie的maxAge设置值
*/
public CustomRememberMeManager()
{
Cookie cookie = new SimpleCookie(DEFAULT_REMEMBER_ME_COOKIE_NAME);
cookie.setHttpOnly(true);
setCookie(cookie);
}
/**
* 重写父类方法,写入Cookie时,先把传过来的有效时间设置到cookie里面在序列化Identity
*/
@Override
public void rememberIdentity(Subject subject, AuthenticationToken token,
AuthenticationInfo authcInfo)
{
UsernamePasswordTokeExtend tokeExtend = (UsernamePasswordTokeExtend) token;
getCookie().setMaxAge(tokeExtend.getRememberMeCookieValue());
super.rememberIdentity(subject, token, authcInfo);
}
}
ChainDefinitionSectionMetaSource
public class ChainDefinitionSectionMetaSource implements
FactoryBean<Ini.Section>
{
private String filterChainDefinitions;
private static final String BLANK_STRING = "";
private Resource webmap = null;
public void setWebmap(Resource resource)
{
this.webmap = resource;
}
public Resource getWebmap()
{
return webmap;
}
@SuppressWarnings("unchecked")
@Override
public Section getObject() throws Exception
{
Ini ini = new Ini();
// 加载默认的url
ini.load(filterChainDefinitions);
Ini.Section section = ini.getSection(Ini.DEFAULT_SECTION_NAME);
// Map<String, List<String>> url2roles = new HashMap<String, List<String>>();
Document doc = XMLUtils.loadXML(webmap.getInputStream());
NodeList groupNodes = doc.getElementsByTagName("group");
int len = groupNodes.getLength();
List<String> list = null;
for (int i = 0; i < len; i++)
{
Element group = (Element) groupNodes.item(i);
String roleStr = group.getAttribute("role");
NodeList menuNodes = group.getElementsByTagName("item");
for (int j = 0; j < menuNodes.getLength(); j++)
{
Element menu = (Element) menuNodes.item(j);
String roleStr1 = menu.getAttribute("role");
String path = BLANK_STRING;
if(menu.getAttribute("path")!=null)
path = menu.getAttribute("path");
NodeList urlNodes = menu.getElementsByTagName("url");
for (int k = 0; k < urlNodes.getLength(); k++)
{
Element url = (Element) urlNodes.item(k);
String roleStr2 = url.getAttribute("role");
String urlString = StringUtils.applyRelativePath(path,url.getTextContent());
if (isBlank(urlString))
continue;
list = null;
if (!isBlank(roleStr2))
{
list = CollectionUtils.arrayToList(StringUtils
.tokenizeToStringArray(roleStr2, ","));
} else if (!isBlank(roleStr1))
{
list = CollectionUtils.arrayToList(StringUtils
.tokenizeToStringArray(roleStr1, ","));
} else if (!isBlank(roleStr))
{
list = CollectionUtils.arrayToList(StringUtils
.tokenizeToStringArray(roleStr, ","));
} else
{
list = Collections.emptyList();
}
// url2roles.put(urlString.trim(), list);
section.put(urlString.trim(), getRoles(list));
}
}
}
return section;
}
@Override
public Class<?> getObjectType()
{
return this.getClass();
}
@Override
public boolean isSingleton()
{
return false;
}
public String getFilterChainDefinitions()
{
return filterChainDefinitions;
}
public void setFilterChainDefinitions(String filterChainDefinitions)
{
this.filterChainDefinitions = filterChainDefinitions;
}
// private
private boolean isBlank(String st)
{
if (st == null || st.trim().equals(BLANK_STRING))
return true;
return false;
}
private String getRoles(List<String> list)
{
if (list.size() == 0)
return BLANK_STRING;
StringBuilder sbBuilder = new StringBuilder();
// sbBuilder.append(",");
for (int i = 0, flag = 1; i < list.size(); i++)
{
String s = list.get(i);
sbBuilder.append("uhomeRoles[");
sbBuilder.append(s);
sbBuilder.append("]");
if (flag % list.size() != 0)
sbBuilder.append(",");
flag++;
}
return sbBuilder.toString();
}
public static void main(String[] args)
{
System.err.println(StringUtils.applyRelativePath("aa/bb/cc/aa.html","aa/bb"));
}
}
CaptchaAuthenticationFilter
public class CaptchaAuthenticationFilter extends FormAuthenticationFilter
{
/**
* 默认验证码参数名称
*/
public static final String DEFAULT_CAPTCHA_PARAM = "captcha";
/**
* 登录次数超出allowLoginNum时,存储在session记录是否展示验证码的key默认名称
*/
public static final String DEFAULT_SHOW_CAPTCHA_KEY_ATTRIBUTE = "showCaptcha";
/**
* 默认在session中存储的登录次数名称
*/
private static final String DEFAULT_LOGIN_NUM_KEY_ATTRIBUTE = "loginNum";
// 验证码参数名称
private String captchaParam = DEFAULT_CAPTCHA_PARAM;
// 在session中的存储验证码的key名称
private String sessionCaptchaKeyAttribute = DEFAULT_CAPTCHA_PARAM;
// 在session中存储的登录次数名称
private String loginNumKeyAttribute = DEFAULT_LOGIN_NUM_KEY_ATTRIBUTE;
// 登录次数超出allowLoginNum时,存储在session记录是否展示验证码的key名称
private String sessionShowCaptchaKeyAttribute = DEFAULT_SHOW_CAPTCHA_KEY_ATTRIBUTE;
// 允许登录次数,当登录次数大于该数值时,会在页面中显示验证码
private Integer allowLoginNum = 1;
@Autowired
private ManagerRoleService managerRoleService;
/**
* 重写父类方法,在shiro执行登录时先对比验证码,正确后在登录,否则直接登录失败
*/
@Override
protected boolean executeLogin(ServletRequest request,
ServletResponse response) throws Exception
{
Session session = getSubject(request, response).getSession();
// 获取登录次数
Integer number = (Integer) session
.getAttribute(getLoginNumKeyAttribute());
// 首次登录,将该数量记录在session中
if (number == null)
{
number = new Integer(1);
session.setAttribute(getLoginNumKeyAttribute(), number);
}
// 获取当前验证码
String currentCaptcha = (String) session
.getAttribute(getSessionCaptchaKeyAttribute());
// 获取用户输入的验证码
String submitCaptcha = getCaptcha(request);
// 如果验证码不匹配,登录失败
if ((submitCaptcha == null || submitCaptcha.length() == 0)
|| !currentCaptcha.equalsIgnoreCase(submitCaptcha))
{
return onLoginFailure(this.createToken(request, response),
new AccountException("验证码不正确"), request, response);
}
return super.executeLogin(request, response);
}
/**
* 设置验证码提交的参数名称
*
* @param captchaParam
* 验证码提交的参数名称
*/
public void setCaptchaParam(String captchaParam)
{
this.captchaParam = captchaParam;
}
/**
* 获取验证码提交的参数名称
*
* @return String
*/
public String getCaptchaParam()
{
return captchaParam;
}
/**
* 设置在session中的存储验证码的key名称
*
* @param sessionCaptchaKeyAttribute
* 存储验证码的key名称
*/
public void setSessionCaptchaKeyAttribute(String sessionCaptchaKeyAttribute)
{
this.sessionCaptchaKeyAttribute = sessionCaptchaKeyAttribute;
}
/**
* 获取设置在session中的存储验证码的key名称
*
* @return Sting
*/
public String getSessionCaptchaKeyAttribute()
{
return sessionCaptchaKeyAttribute;
}
/**
* 获取在session中存储的登录次数名称
*
* @return Stromg
*/
public String getLoginNumKeyAttribute()
{
return loginNumKeyAttribute;
}
/**
* 设置在session中存储的登录次数名称
*
* @param loginNumKeyAttribute
* 登录次数名称
*/
public void setLoginNumKeyAttribute(String loginNumKeyAttribute)
{
this.loginNumKeyAttribute = loginNumKeyAttribute;
}
/**
* 获取用户输入的验证码
*
* @param request
* ServletRequest
*
* @return String
*/
public String getCaptcha(ServletRequest request)
{
return WebUtils.getCleanParam(request, getCaptchaParam());
}
/**
* 获取登录次数超出allowLoginNum时,存储在session记录是否展示验证码的key名称
*
* @return String
*/
public String getSessionShowCaptchaKeyAttribute()
{
return sessionShowCaptchaKeyAttribute;
}
/**
* 设置登录次数超出allowLoginNum时,存储在session记录是否展示验证码的key名称
*
* @param sessionShowCaptchaKeyAttribute
* 是否展示验证码的key名称
*/
public void setSessionShowCaptchaKeyAttribute(
String sessionShowCaptchaKeyAttribute)
{
this.sessionShowCaptchaKeyAttribute = sessionShowCaptchaKeyAttribute;
}
/**
* 获取允许登录次数
*
* @return Integer
*/
public Integer getAllowLoginNum()
{
return allowLoginNum;
}
/**
* 设置允许登录次数,当登录次数大于该数值时,会在页面中显示验证码
*
* @param allowLoginNum
* 允许登录次数
*/
public void setAllowLoginNum(Integer allowLoginNum)
{
this.allowLoginNum = allowLoginNum;
}
/**
* 重写父类方法,当登录失败将异常信息设置到request的attribute中
*/
@Override
protected void setFailureAttribute(ServletRequest request,
AuthenticationException ae)
{
if (ae instanceof IncorrectCredentialsException)
{
request.setAttribute(getFailureKeyAttribute(), "用户名密码不正确");
} else
{
request.setAttribute(getFailureKeyAttribute(), ae.getMessage());
}
}
/**
* 重写父类方法,当登录失败次数大于allowLoginNum(允许登录次)时,将显示验证码
*/
@Override
protected boolean onLoginFailure(AuthenticationToken token,
AuthenticationException e, ServletRequest request,
ServletResponse response)
{
// try
// {
// WebUtils.issueRedirect(request, response, getLoginUrl());
// } catch (IOException e1)
// {
//
// e1.printStackTrace();
// }
Session session = getSubject(request, response).getSession(false);
Integer number = (Integer) session
.getAttribute(getLoginNumKeyAttribute());
// 如果失败登录次数大于allowLoginNum时,展示验证码
if (number > getAllowLoginNum() - 1)
{
session.setAttribute(getSessionShowCaptchaKeyAttribute(), true);
session.setAttribute(getLoginNumKeyAttribute(), ++number);
}
session.setAttribute(getLoginNumKeyAttribute(), ++number);
setFailureAttribute(request, e);
return true;
}
/**
* 重写父类方法,当登录成功后,将allowLoginNum(允许登录次)设置为0,重置下一次登录的状态
*/
@Override
protected boolean onLoginSuccess(AuthenticationToken token,
Subject subject, ServletRequest request, ServletResponse response)
throws Exception
{
Session session = subject.getSession(false);
session.removeAttribute(getLoginNumKeyAttribute());
session.removeAttribute(getSessionShowCaptchaKeyAttribute());
CommonVariableModel cvm = (CommonVariableModel) subject.getPrincipal();
String role = null;
if (cvm.getUser() != null)
{
role = cvm.getUser().getRole();
} else if (cvm.getManager() != null)
{
role = cvm.getManager().getRole();
}
HttpUser user = new HttpUser(role);
ManagerRole role1 = managerRoleService.findByCode(role);
user.appendRole(((UsernamePasswordToken) token).getUsername(),
role1.getId());
session.setAttribute(CommonAction.MANAGER_SESSION_CODE, user);
return super.onLoginSuccess(token, subject, request, response);
}
/**
* 重写父类方法,创建一个自定义的{@link UsernamePasswordTokeExtend}
*/
@Override
protected AuthenticationToken createToken(ServletRequest request,
ServletResponse response)
{
String username = getUsername(request);
String password = getPassword(request);
String host = getHost(request);
boolean rememberMe = false;
String rememberMeValue = request.getParameter(getRememberMeParam());
Integer rememberMeCookieValue = null;
// 如果提交的rememberMe参数存在值,将rememberMe设置成true
if (!(rememberMeValue == null || rememberMeValue.length() == 0))
{
rememberMe = true;
rememberMeCookieValue = CaptchaAuthenticationFilter.toInt(
rememberMeValue, 0);
}
return new UsernamePasswordTokeExtend(username, password, rememberMe,
host, rememberMeCookieValue);
}
// @Override
// protected boolean isLoginRequest(ServletRequest request, ServletResponse
// response) {
// return pathsMatch("/manager/login_submit.do", request);
// }
/**
* UsernamePasswordToke扩展,添加一个rememberMeValue字段,获取提交上来的rememberMe值
* 根据该rememberMe值去设置Cookie的有效时间。
*
* @author vincent
*
*/
@SuppressWarnings("serial")
protected class UsernamePasswordTokeExtend extends UsernamePasswordToken
{
// rememberMe cookie的有效时间
private Integer rememberMeCookieValue;
public UsernamePasswordTokeExtend()
{
}
public UsernamePasswordTokeExtend(String username, String password,
boolean rememberMe, String host, Integer rememberMeCookieValue)
{
super(username, password, rememberMe, host);
this.rememberMeCookieValue = rememberMeCookieValue;
}
/**
* 获取rememberMe cookie的有效时间
*
* @return Integer
*/
public Integer getRememberMeCookieValue()
{
return rememberMeCookieValue;
}
/**
* 设置rememberMe cookie的有效时间
*
* @param rememberMeCookieValue
* cookie的有效时间
*/
public void setRememberMeCookieValue(Integer rememberMeCookieValue)
{
this.rememberMeCookieValue = rememberMeCookieValue;
}
}
private static int toInt(String str, int defaultValue)
{
if (str == null)
{
return defaultValue;
}
try
{
return Integer.parseInt(str);
} catch (NumberFormatException nfe)
{
return defaultValue;
}
}
}
com.haier.uhome.hr91.util.shiro.UhomeRolesAuthorizationFilter
package com.haier.uhome.hr91.util.shiro;
import static org.apache.shiro.util.StringUtils.split;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.Filter;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.apache.shiro.web.filter.authz.RolesAuthorizationFilter;
public class UhomeRolesAuthorizationFilter extends RolesAuthorizationFilter
{
@Override
public Filter processPathConfig(String path, String config)
{
@SuppressWarnings("unchecked")
List<String[]> list = (List<String[]>) this.appliedPaths.get(path);
if (config != null)
{
if (list == null)
list = new ArrayList<String[]>();
list.add(split(config));
}
this.appliedPaths.put(path, list);
return this;
}
@SuppressWarnings("unchecked")
@Override
protected boolean preHandle(ServletRequest request, ServletResponse response)
throws Exception
{
if (this.appliedPaths == null || this.appliedPaths.isEmpty())
{
// if (log.isTraceEnabled()) {
// log.trace("appliedPaths property is null or empty. This Filter will passthrough immediately.");
// }
return true;
}
for (String path : this.appliedPaths.keySet())
{
// If the path does match, then pass on to the subclass
// implementation for specific checks
// (first match 'wins'):
if (pathsMatch(path, request))
{
// log.trace("Current requestURI matches pattern '{}'. Determining filter chain execution...",
// path);
Object config = this.appliedPaths.get(path);
List<String[]> configList = (List<String[]>) config;
if (configList != null)
{
for (String[] arr : configList)
{
if (isFilterChainContinued(request, response, path, arr))
return true;
}
return false;
} else
return isFilterChainContinued(request, response, path,
config);
}
}
// no path matched, allow the request to go through:
return true;
}
private boolean isFilterChainContinued(ServletRequest request,
ServletResponse response, String path, Object pathConfig)
throws Exception
{
if (isEnabled(request, response, path, pathConfig))
{ // isEnabled check added in 1.2
// if (log.isTraceEnabled())
// {
// log.trace(
// "Filter '{}' is enabled for the current request under path '{}' with config [{}]. "
// +
// "Delegating to subclass implementation for 'onPreHandle' check.",
// new Object[] { getName(), path, pathConfig });
// }
// The filter is enabled for this specific request, so delegate to
// subclass implementations
// so they can decide if the request should continue through the
// chain or not:
return onPreHandle(request, response, pathConfig);
}
// if (log.isTraceEnabled())
// {
// log.trace(
// "Filter '{}' is disabled for the current request under path '{}' with config [{}]. "
// + "The next element in the FilterChain will be called immediately.",
// new Object[] { getName(), path, pathConfig });
// }
// This filter is disabled for this specific request,
// return 'true' immediately to indicate that the filter will not
// process the request
// and let the request/response to continue through the filter chain:
return true;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<root>
<group role="manager" title="社区管理" expand="true">
<item url="comm/user_list.do" title="社区业户" path="/manager/comm/">
<url>user_list.do</url>
</item>
<item role="manager,admin" url="comm/user_group_list.do" title="业户群组" path="/manager/comm/">
<url>user_group_list.do</url>
</item>
<item url="comm/car_list.do" title="业户车辆" path="/manager/comm/">
<url>car_list.do</url>
</item>
<item url="comm/bodyguard_list.do" title="社区保安 " path="/manager/comm/">
<url>bodyguard_list.do</url>
</item>
<item url="comm/log_patrol_list.do" title="巡更记录 " path="/manager/comm/">
<url>log_patrol_list.do</url>
</item>
</group>
<group role="admin" title="终端管理" expand="true">
<item url="device/community_list.do" title="小区结构 " path="/manager/device/">
<url>community_list.do</url>
</item>
<item url="device/device_model_list.do" title="终端型号 " path="/manager/device/">
<url>device_model_list.do</url>
</item>
<item url="device/device_list.do" title="终端设备 " path="/manager/device/">
<url>device_list.do</url>
</item>
<item url="device/device_scan.do" title="扫描终端 " path="/manager/device/">
<url>/manager/device/device_scan.do</url>
</item>
<item url="device/device_remote_control_list.do" title="终端远程控制 " path="/manager/device/">
<url>device_remote_control_list.do</url>
</item>
<item url="device/device_soft_list.do" title="升级软件管理 " path="/manager/device/">
<url>device_soft_list.do</url>
</item>
<item url="device/update_select_device.do" title="终端升级 " path="/manager/device/">
<url>update_select_device.do</url>
</item>
<item url="device/update_info.do" title="终端升级信息 " path="/manager/device/">
<url>update_info.do</url>
</item>
</group>
<group role="manager" title="IC卡管理" expand="true" >
<item url="card/card_add.do" title="IC卡注册 " path="/manager/card/">
<url>card_add.do</url>
</item>
<item url="card/card_list.do" title="IC卡列表 " path="/manager/card/">
<url>card_list.do</url>
</item>
<item url="card/card_send_select_dev.do" title="IC卡下发 " path="/manager/card/">
<url>card_send_select_dev.do</url>
</item>
<item url="card/card_imp_exp.do" title="IC卡信息维护 " path="/manager/card/">
<url>card_imp_exp.do</url>
</item>
</group>
<group role="manager" title="门禁管理" expand="true">
<item url="pwd/pwd_comm_select_dev.do" title="设置小区门禁密码 " path="/manager/pwd/">
<url>pwd_comm_select_dev.do</url>
</item>
<item url="pwd/pwd_unit_select_dev.do" title="设置单元门禁密码 " path="/manager/pwd/">
<url>pwd_unit_select_dev.do</url>
</item>
<item url="pwd/pwd_send_select_dev.do" title="密码下发 " path="/manager/pwd/">
<url>pwd_send_select_dev.do</url>
</item>
</group>
<group role="manager" title="社区服务" expand="true">
<item url="commserv/bill_select_user.do" title="物业收费" path="/manager/commserv/">
<url>bill_select_user.do</url>
</item>
<item url="commserv/weather_view.do" title="天气预报" path="/manager/commserv/">
<url>weather_view.do</url>
</item>
</group>
<group role="manager" title="日志管理" expand="true">
<item url="log/log_startup_list.do" title="系统启动日志 " path="/manager/log/">
<url>log_startup_list.do</url>
</item>
<item url="log/log_device_startup_list.do" title="终端启动日志 " path="/manager/log/">
<url>log_device_startup_list.do</url>
</item>
<item url="log/log_callup_list.do" title="呼叫日志 " path="/manager/log/">
<url>log_callup_list.do</url>
</item>
<item url="log/log_alert_list.do" title="报警日志" path="/manager/log/">
<url>log_alert_list.do</url>
</item>
<item url="log/log_alert_turnoff_list.do" title="解除报警日志 " path="/manager/log/">
<url>log_alert_turnoff_list.do</url>
</item>
<item url="log/log_comm_door_list.do" title="小区开门日志 " path="/manager/log/">
<url>log_comm_door_list.do</url>
</item>
<item url="log/log_unit_door_list.do" title="单元开门日志 " path="/manager/log/">
<url>log_unit_door_list.do</url>
</item>
</group>
<group role="admin" title="DVR管理" expand="true">
<item url="dvr/dvr_server_list.do" title="DVR服务器 " path="/manager/dvr/">
<url>dvr_server_list.do</url>
</item>
<item url="dvr/dvr_camera_list.do" title="DVR摄像头" path="/manager/dvr/">
<url>dvr_camera_list.do</url>
</item>
</group>
<group role="admin" title="系统参数设置" expand="true">
<item url="sys/config.do" title="系统参数 " path="/manager/sys/">
<url>config.do</url>
</item>
<item url="sys/reg.do" title="系统注册 " path="/manager/sys/">
<url>reg.do</url>
</item>
<item url="sys/manager_list.do" title="系统管理员 " path="/manager/sys/">
<url>manager_list.do</url>
</item>
<item url="sys/db_backup_list.do" title="数据备份 " path="/manager/sys/">
<url>db_backup_list.do</url>
</item>
<item url="sys/update_pwd.do" title="修改密码 " path="/manager/sys/">
<url>update_pwd.do</url>
</item>
</group>
</root>