李宇
2021-01-28 2f52e8c752122625f189ae7657e621db0d6d253c
修改安全测评内容
已修改20个文件
已添加6个文件
1091 ■■■■■ 文件已修改
src/main/java/com/nanometer/smartlab/api/ApiAction.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/nanometer/smartlab/api/schedule/ReagentSyncSchedule.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/nanometer/smartlab/api/schedule/UserPointSchedule.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/nanometer/smartlab/controller/LoginController.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/nanometer/smartlab/email/EmailSendSchedule.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/nanometer/smartlab/entity/OpeApply.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/nanometer/smartlab/realm/RetryLimitCredentialsMatcher.java 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/nanometer/smartlab/realm/ShiroDbRealm.java 109 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/nanometer/smartlab/realm/ShiroSpringCache.java 113 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/nanometer/smartlab/realm/ShiroSpringCacheManager.java 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/nanometer/smartlab/service/InterfaceServiceImpl.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/nanometer/smartlab/service/OpeApplyServiceImpl.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/nanometer/smartlab/service/OpeOrderServiceImpl.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/nanometer/smartlab/service/OpeReagentStatusServiceImpl.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/nanometer/smartlab/service/OpeUseFlowServiceImpl.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/nanometer/smartlab/service/OpeWarehouseReserveServiceImpl.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/nanometer/smartlab/service/SysControllerServiceImpl.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/nanometer/smartlab/util/Validator.java 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/apache/shiro/web/filter/InvalidRequestFilter.java 88 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/springframework/web/filter/DelegatingFilterProxy.java 409 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/WEB-INF/spring-mvc.xml 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/WEB-INF/spring-shiro.xml 47 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/WEB-INF/test/test.properties 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/index.xhtml 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/login.xhtml 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/user_mng.xhtml 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/nanometer/smartlab/api/ApiAction.java
@@ -28,6 +28,7 @@
import org.apache.shiro.subject.Subject;
import org.primefaces.context.RequestContext;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
@@ -49,46 +50,55 @@
public class ApiAction extends BaseAction {
    private static Logger logger = Logger.getLogger(ApiAction.class);
    @Lazy
    @Resource
    private SysUserService sysUserService;
    @Lazy
    @Resource
    private OpeReagentStatusService opeReagentStatusService;
    @Resource
    private SysReagentService sysReagentService;
    @Lazy
    @Resource
    private SysWarehouseContainerService sysWarehouseContainerService;
    @Lazy
    @Resource
    private SysLaboratoryContainerService sysLaboratoryContainerService;
    @Lazy
    @Resource
    private BaseMetaService baseMetaService;
    @Lazy
    @Resource
    private InterfaceService interfaceService;
    @Lazy
    @Resource
    private SysWarehouseService sysWarehouseService;
    @Resource
    private SysWarningService sysWarningService;
    @Lazy
    @Resource
    private TempSensorsService tempSensorsService;
    @Lazy
    @Resource
    private SysFileService sysFileService;
    @Lazy
    @Resource
    private SysLaboratoryContainerDao sysLaboratoryContainerDao;
    @Lazy
    @Resource
    private SysWarehouseContainerDao sysWarehouseContainerDao;
    @Lazy
    @Resource
    private DangerousEncodeService dangerousEncodeService;
    @Lazy
    @Resource
    private EncodeReplaceDictService encodeReplaceDictService;
    @Lazy
    @Resource
    private SysLaboratoryService sysLaboratoryService;
    @Lazy
    @Resource
    private HazardousWasteService hazardousWasteService;
    @Lazy
    @Resource
    private OpeLaboratoryReserveService opeLaboratoryReserveService;
    @Lazy
    @Resource
    private OpeUseFlowService opeUseFlowService;
    @Value("${institute.url}")
src/main/java/com/nanometer/smartlab/api/schedule/ReagentSyncSchedule.java
@@ -7,6 +7,7 @@
import org.apache.commons.lang.time.DateFormatUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
@@ -40,14 +41,19 @@
    private String reagentStatusUrl;
    @Value("${sensors.url}")
    private String reagentSensorsUrl;
    @Lazy
    @Resource
    private BaseMetaService baseMetaService;
    @Lazy
    @Resource
    private OpeReagentStatusService reagentStatusService;
    @Lazy
    @Resource
    private OpeUseFlowService opeUseFlowService;
    @Lazy
    @Resource
    private SysContainerSensorsService sysContainerSensorsService;
    @Lazy
    @Resource
    private SysUserService sysUserService;
src/main/java/com/nanometer/smartlab/api/schedule/UserPointSchedule.java
@@ -3,6 +3,7 @@
import com.nanometer.smartlab.service.SysUserService;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@@ -11,6 +12,7 @@
@Component
public class UserPointSchedule {
    private static Logger logger = Logger.getLogger(UserPointSchedule.class);
    @Lazy
    @Autowired
    private SysUserService sysUserService;
src/main/java/com/nanometer/smartlab/controller/LoginController.java
@@ -6,6 +6,7 @@
import com.nanometer.smartlab.util.FacesUtils;
import org.apache.log4j.Logger;
import org.apache.shiro.authc.DisabledAccountException;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
@@ -42,6 +43,9 @@
        } catch (UnknownAccountException e) {
            FacesUtils.warn("用户名不存在");
            return null;
        }  catch (ExcessiveAttemptsException e) {
            FacesUtils.warn("登陆失败,密码连续输入错误超过5次,锁定5分钟!");
            return null;
        } catch (Exception e) {
            logger.error("登陆失败", e);
        }
src/main/java/com/nanometer/smartlab/email/EmailSendSchedule.java
@@ -6,6 +6,7 @@
import com.nanometer.smartlab.service.*;
import com.nanometer.smartlab.util.EmailSend;
import org.apache.log4j.Logger;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@@ -17,7 +18,7 @@
 */
@Component
public class EmailSendSchedule {
    @Lazy
    @Resource
    private OpeOrderService opeOrderService;
src/main/java/com/nanometer/smartlab/entity/OpeApply.java
@@ -2,6 +2,7 @@
import com.nanometer.smartlab.entity.enumtype.ApplyStatus;
import com.nanometer.smartlab.entity.enumtype.ValidFlag;
import com.nanometer.smartlab.util.Validator;
import java.io.Serializable;
import java.math.BigDecimal;
@@ -132,7 +133,7 @@
    }
    public void setApplyGoal(String applyGoal) {
        this.applyGoal = applyGoal;
        this.applyGoal = Validator.filter(applyGoal);
    }
    public String getId() {
@@ -156,7 +157,7 @@
    }
    public void setNum(Integer num) {
        this.num = num;
        this.num = Integer.parseInt(Validator.filter(num.toString()));
    }
    public String getApplyUserId() {
@@ -172,7 +173,7 @@
    }
    public void setObjective(String objective) {
        this.objective = objective;
        this.objective = Validator.filter(objective);
    }
    public Timestamp getCreateTime() {
@@ -210,7 +211,7 @@
        this.beforeApproveUserId=beforeApproveUserId;
    }
    public void setApproveUserId(String approveUserId) {
        this.approveUserId = approveUserId;
        this.approveUserId = Validator.filter(approveUserId);
    }
    public String getMemo() {
src/main/java/com/nanometer/smartlab/realm/RetryLimitCredentialsMatcher.java
对比新文件
@@ -0,0 +1,87 @@
/**
 * The MIT License (MIT)
 * Copyright (c) 2016 Dreamlu (596392912@qq.com).
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
package com.nanometer.smartlab.realm;
import org.apache.log4j.Logger;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheManager;
import org.springframework.beans.factory.InitializingBean;
import java.util.concurrent.atomic.AtomicInteger;
/**
 * 输错5次密码锁定半小时,ehcache.xml配置
 *
 */
public class RetryLimitCredentialsMatcher extends HashedCredentialsMatcher implements InitializingBean {
    private final static Logger logger = Logger.getLogger(RetryLimitCredentialsMatcher.class);
    private final static String DEFAULT_CHACHE_NAME = "retryLimitCache";
    private final CacheManager cacheManager;
    private String retryLimitCacheName;
    private Cache<String, AtomicInteger> passwordRetryCache;
    public RetryLimitCredentialsMatcher(CacheManager cacheManager) {
        this.cacheManager = cacheManager;
        this.retryLimitCacheName = DEFAULT_CHACHE_NAME;
    }
    public String getRetryLimitCacheName() {
        return retryLimitCacheName;
    }
    public void setRetryLimitCacheName(String retryLimitCacheName) {
        this.retryLimitCacheName = retryLimitCacheName;
    }
    @Override
    public boolean doCredentialsMatch(AuthenticationToken authcToken, AuthenticationInfo info) {
        String username = (String) authcToken.getPrincipal();
        //retry count + 1
        AtomicInteger retryCount = passwordRetryCache.get(username);
        if(retryCount == null) {
            retryCount = new AtomicInteger(0);
            passwordRetryCache.put(username, retryCount);
        }
        if(retryCount.incrementAndGet() > 5) {
            //if retry count > 5 throw
            logger.warn("username: " + username + " tried to login more than 5 times in period");
//            FacesUtils.warn("用户名: " + username + " 密码连续输入错误超过5次,锁定5分钟!");
            throw new ExcessiveAttemptsException("用户名: " + username + " 密码连续输入错误超过5次,锁定5分钟!");
        }
        boolean matches = super.doCredentialsMatch(authcToken, info);
        if(matches) {
            //clear retry data
            passwordRetryCache.remove(username);
        }
        return matches;
    }
    @Override
    public void afterPropertiesSet() throws Exception {
        this.passwordRetryCache = cacheManager.getCache(retryLimitCacheName);
    }
}
src/main/java/com/nanometer/smartlab/realm/ShiroDbRealm.java
对比新文件
@@ -0,0 +1,109 @@
package com.nanometer.smartlab.realm;
import com.nanometer.smartlab.entity.BaseRolePage;
import com.nanometer.smartlab.entity.SysUser;
import com.nanometer.smartlab.service.BaseRolePageService;
import com.nanometer.smartlab.service.SysUserService;
import com.nanometer.smartlab.util.Constants;
import org.apache.log4j.Logger;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.Subject;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
/**
 * @description:shiro权限认证
 * @author:zhixuan.wang
 * @date:2015/10/1 14:51
 */
public class ShiroDbRealm extends AuthorizingRealm {
    private static Logger LOGGER = Logger.getLogger(ShiroDbRealm.class);
    @Resource
    private SysUserService sysUserService;
    @Resource
    private BaseRolePageService baseRolePageService;
    public ShiroDbRealm(CacheManager cacheManager, CredentialsMatcher matcher) {
        super(cacheManager, matcher);
    }
    /**
     * Shiro登录认证(原理:用户提交 用户名和密码  --- shiro 封装令牌 ---- realm 通过用户名将密码查询返回 ---- shiro 自动去比较查询出密码和用户输入密码是否一致---- 进行登陆控制 )
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
        final String account = String.valueOf(usernamePasswordToken.getUsername());
        SysUser user = this.sysUserService.getSysUserByAccount(account);
        if (user == null) {
            throw new UnknownAccountException();
        }
        AuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user.getAccount(), user.getPassword(), getName());
        return authenticationInfo;
    }
    /**
     * Shiro权限认证
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(
            PrincipalCollection principals) {
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        String account = (String) super.getAvailablePrincipal(principals);
        List<String> roles = new ArrayList<String>();
        List<String> permissions = new ArrayList<String>();
        SysUser user = this.sysUserService.getSysUserByAccount(account);
        if(user != null && user.getRoleId() != null) {
            roles.add(user.getRoleName());
            List<BaseRolePage> baseRolePageList = baseRolePageService.getBaseRolePageList(user.getRoleId(), null);
            if (baseRolePageList != null && baseRolePageList.size() > 0) {
                for (BaseRolePage baseRolePage : baseRolePageList) {
                    permissions.add(baseRolePage.getPageId());
                }
            }
        }
        info.addRoles(roles);
        info.addStringPermissions(permissions);
        return info;
    }
    @Override
    public void onLogout(PrincipalCollection principals) {
        Subject currentUser = SecurityUtils.getSubject();
        currentUser.getSession(true).removeAttribute(Constants.SESSION_USER);
        super.onLogout(principals);
    }
    /**
     * 清除用户缓存
     * @param loginName
     */
    public void removeUserCache(String loginName){
        Cache<Object, AuthenticationInfo> cache = getAuthenticationCache();
        if (null != cache){
            cache.remove(loginName);
        }
        SimplePrincipalCollection principals = new SimplePrincipalCollection();
        principals.add(loginName, super.getName());
        super.clearCachedAuthenticationInfo(principals);
    }
}
src/main/java/com/nanometer/smartlab/realm/ShiroSpringCache.java
对比新文件
@@ -0,0 +1,113 @@
/**
 * The MIT License (MIT)
 * Copyright (c) 2016 Dreamlu (596392912@qq.com).
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
package com.nanometer.smartlab.realm;
import org.apache.log4j.Logger;
import org.apache.shiro.cache.CacheException;
import org.springframework.cache.Cache;
import org.springframework.cache.Cache.ValueWrapper;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
/**
 * 使用spring-cache作为shiro缓存
 *
 *
 */
@SuppressWarnings("unchecked")
public class ShiroSpringCache<K, V> implements org.apache.shiro.cache.Cache<K, V> {
    private static final Logger logger = Logger.getLogger(ShiroSpringCache.class);
    private final Cache cache;
    public ShiroSpringCache(Cache cache) {
        if (cache == null) {
            throw new IllegalArgumentException("Cache argument cannot be null.");
        }
        this.cache = cache;
    }
    @Override
    public V get(K key) throws CacheException {
        if (logger.isTraceEnabled()) {
            logger.trace("Getting object from cache [" + this.cache.getName() + "] for key [" + key + "]key type:" + key.getClass());
        }
        ValueWrapper valueWrapper = cache.get(key);
        if (valueWrapper == null) {
            if (logger.isTraceEnabled()) {
                logger.trace("Element for [" + key + "] is null.");
            }
            return null;
        }
        return (V) valueWrapper.get();
    }
    @Override
    public V put(K key, V value) throws CacheException {
        if (logger.isTraceEnabled()) {
            logger.trace("Putting object in cache [" + this.cache.getName() + "] for key [" + key + "]key type:" + key.getClass());
        }
        V previous = get(key);
        cache.put(key, value);
        return previous;
    }
    @Override
    public V remove(K key) throws CacheException {
        if (logger.isTraceEnabled()) {
            logger.trace("Removing object from cache [" + this.cache.getName() + "] for key [" + key + "]key type:" + key.getClass());
        }
        V previous = get(key);
        cache.evict(key);
        return previous;
    }
    @Override
    public void clear() throws CacheException {
        if (logger.isTraceEnabled()) {
            logger.trace("Clearing all objects from cache [" + this.cache.getName() + "]");
        }
        cache.clear();
    }
    @Override
    public int size() {
        return 0;
    }
    @Override
    public Set<K> keys() {
        return Collections.emptySet();
    }
    @Override
    public Collection<V> values() {
        return Collections.emptySet();
    }
    @Override
    public String toString() {
        return "ShiroSpringCache [" + this.cache.getName() + "]";
    }
}
src/main/java/com/nanometer/smartlab/realm/ShiroSpringCacheManager.java
对比新文件
@@ -0,0 +1,63 @@
/**
 * The MIT License (MIT)
 * Copyright (c) 2016 Dreamlu (596392912@qq.com).
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
package com.nanometer.smartlab.realm;
import org.apache.log4j.Logger;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.util.Destroyable;
/**
 * 使用spring-cache作为shiro缓存
 * 缓存管理器
 * @author L.cm
 *
 */
public class ShiroSpringCacheManager implements CacheManager, Destroyable {
    private static final Logger logger = Logger.getLogger(ShiroSpringCacheManager.class);
    private org.springframework.cache.CacheManager cacheManager;
    public org.springframework.cache.CacheManager getCacheManager() {
        return cacheManager;
    }
    public void setCacheManager(org.springframework.cache.CacheManager cacheManager) {
        this.cacheManager = cacheManager;
    }
    @Override
    public <K, V> Cache<K, V> getCache(String name) throws CacheException {
        if (logger.isTraceEnabled()) {
            logger.trace("Acquiring ShiroSpringCache instance named [" + name + "]");
        }
        org.springframework.cache.Cache cache = cacheManager.getCache(name);
        return new ShiroSpringCache<K, V>(cache);
    }
    @Override
    public void destroy() throws Exception {
        cacheManager = null;
    }
}
src/main/java/com/nanometer/smartlab/service/InterfaceServiceImpl.java
@@ -22,6 +22,7 @@
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@@ -39,7 +40,7 @@
public class InterfaceServiceImpl implements InterfaceService {
    private static Logger logger = Logger.getLogger(ApiAction.class);
    @Lazy
    @Resource
    private OpeUseFlowService opeUseFlowService;
    @Resource
src/main/java/com/nanometer/smartlab/service/OpeApplyServiceImpl.java
@@ -15,6 +15,7 @@
import com.nanometer.smartlab.util.MessageUtil;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.context.annotation.Lazy;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.DuplicateKeyException;
@@ -41,10 +42,13 @@
    @Resource(name = "opeApplyDao")
    OpeApplyDao opeApplyDao;
    @Lazy
    @Resource
    OpeOrderService opeOrderService;
    @Lazy
    @Resource
    OpeReagentStatusService opeReagentStatusService;
    @Lazy
    @Resource
    OpeWarehouseReserveService opeWarehouseReserveService;
src/main/java/com/nanometer/smartlab/service/OpeOrderServiceImpl.java
@@ -17,6 +17,7 @@
import com.nanometer.smartlab.util.MessageUtil;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.context.annotation.Lazy;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.DuplicateKeyException;
@@ -49,10 +50,13 @@
    private SysSequenceService sysSequenceService;
    @Resource
    private OpeApplyService opeApplyService;
    @Lazy
    @Resource
    private OpeReagentStatusService opeReagentStatusService;
    @Lazy
    @Resource
    private OpeWarehouseReserveService opeWarehouseReserveService;
    @Lazy
    @Resource
    private OpeUseFlowService opeUseFlowService;
    @Resource
src/main/java/com/nanometer/smartlab/service/OpeReagentStatusServiceImpl.java
@@ -12,6 +12,7 @@
import com.nanometer.smartlab.entity.enumtype.ValidFlag;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.context.annotation.Lazy;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.DuplicateKeyException;
@@ -40,9 +41,10 @@
    @Resource(name = "opeReagentStatusDao")
    OpeReagentStatusDao opeReagentStatusDao;
    @Lazy
    @Resource
    private OpeWarehouseReserveService opeWarehouseReserveService;
    @Lazy
    @Resource
    private OpeUseFlowService opeUseFlowService;
    @Resource
src/main/java/com/nanometer/smartlab/service/OpeUseFlowServiceImpl.java
@@ -55,8 +55,6 @@
    @Resource
    private OpeReagentStatusService opeReagentStatusService;
    @Resource
    private OpeUseFlowService opeUseFlowService;
    @Resource
    private SysReagentService sysReagentService;
    @Resource
    private BaseMetaDao baseMetaDao;
@@ -389,11 +387,11 @@
                for (String statusId : codeTmp) {
                    String code = opeReagentStatusService.getOpeReagentStatus(statusId).getReagentCode();
                    //此时状态为领用待入库
                    opeUseFlowService.updateReceiptNumber(code, receiptNumber);
                    this.updateReceiptNumber(code, receiptNumber);
                }
            }else{
                for (String code : codeTmp) {
                    opeUseFlowService.updateReceiptNumber(code, receiptNumber);
                    this.updateReceiptNumber(code, receiptNumber);
                }
            }
@@ -443,11 +441,11 @@
                for (String statusId : codeTmp) {
                    String code = opeReagentStatusService.getOpeReagentStatus(statusId).getReagentCode();
                    //此时状态为领用待入库
                    opeUseFlowService.updateReceiptNumber(code, receiptNumber);
                    this.updateReceiptNumber(code, receiptNumber);
                }
            }else{
                for (String code : codeTmp) {
                    opeUseFlowService.updateReceiptNumber(code, receiptNumber);
                    this.updateReceiptNumber(code, receiptNumber);
                }
            }
src/main/java/com/nanometer/smartlab/service/OpeWarehouseReserveServiceImpl.java
@@ -48,8 +48,6 @@
    @Resource
    private OpeUseFlowService opeUseFlowService;
    @Resource
    private OpeWarehouseReserveService opeWarehouseReserveService;
    @Resource(name="baseMetaDao")
    private BaseMetaDao baseMetaDao;
@@ -596,8 +594,7 @@
    @Transactional
    public void insertOpeWarehouseReserve2(OpeApplyReserve opeApplyReserve, OpeOrder oo) {
        OpeWarehouseReserve ope = this.opeWarehouseReserveService
                .getOpeWarehouseReserve2(opeApplyReserve.getReagent().getId(), opeApplyReserve.getArticleNumber(),opeApplyReserve.getHouseId());
        OpeWarehouseReserve ope = this.getOpeWarehouseReserve2(opeApplyReserve.getReagent().getId(), opeApplyReserve.getArticleNumber(),opeApplyReserve.getHouseId());
        if (ope == null) {
            ope = new OpeWarehouseReserve();
@@ -619,7 +616,7 @@
            opeWarehouseReserveDao.insertOpeWarehouseReserve2(ope);
        }else {
            ope.setReserve(ope.getReserve() + opeApplyReserve.getArrivalNum());
            this.opeWarehouseReserveService.updateOpeWarehouseReserve(ope);
            this.updateOpeWarehouseReserve(ope);
        }
@@ -686,7 +683,7 @@
            List<OpeWarehouseReserve> cacheUpdateList = oar.getCacheUpdateList();
            for (OpeWarehouseReserve owr : cacheUpdateList) {
                //1.根据仓库id和试剂id搜索不同批号的试剂库存
                List<OpeWarehouseReserve> reserveList = opeWarehouseReserveService
                List<OpeWarehouseReserve> reserveList = this
                        .selectWarehouseByRidAndArticleNumberAndWarehouse(reagentId, owr.getArticleNumber(), owr.getWarehouseId());
                Integer numLeave = owr.getUseNum();
@@ -732,7 +729,7 @@
                    
                    //更新库存
                    opeWarehouseReserveService.updateBtReserve(warehouseReserve.getId(),usedNum);
                    this.updateBtReserve(warehouseReserve.getId(),usedNum);
                    if (numLeave < 1) {
                        break;
                    }
@@ -819,7 +816,7 @@
            // 仓库库存update
            opeWarehouseReserve = this.opeWarehouseReserveService.getOpeWarehouseReserve2(opeApply.getReagent().getId(), opeApply.getArticleNumber(),opeApply.getHouseId());
            opeWarehouseReserve = this.getOpeWarehouseReserve2(opeApply.getReagent().getId(), opeApply.getArticleNumber(),opeApply.getHouseId());
            if (opeWarehouseReserve == null) {
                opeWarehouseReserve = new OpeWarehouseReserve();
                opeWarehouseReserve.setReagentId(opeApply.getReagent().getId());
@@ -830,9 +827,9 @@
            }
            opeWarehouseReserve.setReserve(opeWarehouseReserve.getReserve() + opeApply.getArrivalNum());
            if (StringUtils.isBlank(opeWarehouseReserve.getId())) {
                this.opeWarehouseReserveService.insertOpeWarehouseReserve(opeWarehouseReserve);
                this.insertOpeWarehouseReserve(opeWarehouseReserve);
            } else {
                this.opeWarehouseReserveService.updateOpeWarehouseReserve(opeWarehouseReserve);
                this.updateOpeWarehouseReserve(opeWarehouseReserve);
            }
        }
    }
src/main/java/com/nanometer/smartlab/service/SysControllerServiceImpl.java
@@ -38,8 +38,6 @@
    SysControllerDao sysControllerDao;
    @Resource(name = "sysLaboratoryContainerDao")
    SysLaboratoryContainerDao sysLaboratoryContainerDao;
    @Resource(name = "sysControllerService")
    SysControllerService sysControllerService;
    @Resource(name = "baseMetaService")
    BaseMetaService baseMetaService;
    @Override
@@ -114,7 +112,7 @@
    @Override
    public void uploadFile(FileUploadEvent event) throws  Exception{
        List<SysController> sysControllers=sysControllerService.getAllControllerList();
        List<SysController> sysControllers=this.getAllControllerList();
        List<BaseMeta> typeList=baseMetaService.getBaseMetaList("controller_type");
        //主控名字和条码
        HashSet<String> controllerInfo = new HashSet<>();
@@ -196,7 +194,7 @@
                sysController.setControllerCode(controlCode);
                sysController.setControllerName(controlName);
                sysController.setType(typeMap.get(controlType));
                sysControllerService.insertSysController(sysController);
                this.insertSysController(sysController);
                controllerInfo.add(controlName);
                controllerInfo.add(controlCode);
            }
src/main/java/com/nanometer/smartlab/util/Validator.java
对比新文件
@@ -0,0 +1,48 @@
package com.nanometer.smartlab.util;
public class Validator {
    public static String filter(String value) {
        if (value == null) {
            return null;
        }
        StringBuffer result = new StringBuffer(value.length());
        for (int i = 0; i < value.length(); ++i){
            switch (value.charAt(i)) {
                case '<':
                    result.append("&lt;");
                    break;
                case '>':
                    result.append("&gt;");
                    break;
                case '"':
                    result.append("&quot;");
                    break;
                case '\'':
                    result.append("&#39;");
                    break;
                case '%':
                    result.append("&#37;");
                    break;
                case ';':
                    result.append("&#59;");
                    break;
                case '(':
                    result.append("&#40;");
                    break;
                case ')':
                    result.append("&#41;");
                    break;
                case '&':
                    result.append("&amp;");
                    break;
                case '+':
                    result.append("&#43;");
                    break;
                default:
                    result.append(value.charAt(i));
                    break;
            }
        }
        return result.toString().replaceAll("\\\\","").replaceAll("/", "");
    }
}
src/main/java/org/apache/shiro/web/filter/InvalidRequestFilter.java
@@ -86,50 +86,50 @@
                ctx = WebUtils.toHttp(request).getContextPath();
            }
            // 登录url拼接的jsessionId进行放行
            if(uri.startsWith(ctx + this.getLoginUrl() + ";jsessionid=") ||
                    uri.startsWith(ctx + this.getLoginUrl() + "%3bjsessionid=") ||
                    uri.startsWith(ctx + this.getLoginUrl() + "%3Bjsessionid=") ||
                    uri.startsWith(ctx + "/javax.faces.resource/mybootstrap.css.xhtml;jsessionid=")||
                    uri.startsWith(ctx + "/javax.faces.resource/mybootstrap.css.xhtml%3bjsessionid=")||
                    uri.startsWith(ctx + "/javax.faces.resource/mybootstrap.css.xhtml%3Bjsessionid=")||
                    uri.startsWith(ctx + "/javax.faces.resource/default.css.xhtml;jsessionid=")||
                    uri.startsWith(ctx + "/javax.faces.resource/default.css.xhtml%3bjsessionid=")||
                    uri.startsWith(ctx + "/javax.faces.resource/default.css.xhtml%3Bjsessionid=")||
                    uri.startsWith(ctx + "/javax.faces.resource/components.css.xhtml;jsessionid=")||
                    uri.startsWith(ctx + "/javax.faces.resource/components.css.xhtml%3bjsessionid=")||
                    uri.startsWith(ctx + "/javax.faces.resource/components.css.xhtml%3Bjsessionid=")||
                    uri.startsWith(ctx + "/javax.faces.resource/jquery/jquery-plugins.js.xhtml;jsessionid=")||
                    uri.startsWith(ctx + "/javax.faces.resource/jquery/jquery-plugins.js.xhtml%3bjsessionid=")||
                    uri.startsWith(ctx + "/javax.faces.resource/jquery/jquery-plugins.js.xhtml%3Bjsessionid=")||
                    uri.startsWith(ctx + "/javax.faces.resource/jquery/jquery.js.xhtml;jsessionid=")||
                    uri.startsWith(ctx + "/javax.faces.resource/jquery/jquery.js.xhtml%3bjsessionid=")||
                    uri.startsWith(ctx + "/javax.faces.resource/jquery/jquery.js.xhtml%3Bjsessionid=")||
                    uri.startsWith(ctx + "/javax.faces.resource/core.js.xhtml;jsessionid=")||
                    uri.startsWith(ctx + "/javax.faces.resource/core.js.xhtml%3bjsessionid=")||
                    uri.startsWith(ctx + "/javax.faces.resource/core.js.xhtml%3Bjsessionid=")||
                    uri.startsWith(ctx + "/javax.faces.resource/extra.js.xhtml;jsessionid=")||
                    uri.startsWith(ctx + "/javax.faces.resource/extra.js.xhtml%3bjsessionid=")||
                    uri.startsWith(ctx + "/javax.faces.resource/extra.js.xhtml%3Bjsessionid=")||
                    uri.startsWith(ctx + "/resources/images/logo1.png;jsessionid=")||
                    uri.startsWith(ctx + "/resources/images/logo1.png%3bjsessionid=")||
                    uri.startsWith(ctx + "/resources/images/logo1.png%3Bjsessionid=")||
                    uri.startsWith(ctx + "/javax.faces.resource/components.js.xhtml;jsessionid=")||
                    uri.startsWith(ctx + "/javax.faces.resource/components.js.xhtml%3bjsessionid=")||
                    uri.startsWith(ctx + "/javax.faces.resource/components.js.xhtml%3Bjsessionid=")||
                    uri.startsWith(ctx + "/resources/images/logo.png;jsessionid=")||
                    uri.startsWith(ctx + "/resources/images/logo.png%3bjsessionid=")||
                    uri.startsWith(ctx + "/resources/images/logo.png%3Bjsessionid=")) {
                return false;
            }
//            if(uri.startsWith(ctx + this.getLoginUrl() + ";jsessionid=") ||
//                    uri.startsWith(ctx + this.getLoginUrl() + "%3bjsessionid=") ||
//                    uri.startsWith(ctx + this.getLoginUrl() + "%3Bjsessionid=") ||
//                    uri.startsWith(ctx + "/javax.faces.resource/mybootstrap.css.xhtml;jsessionid=")||
//                    uri.startsWith(ctx + "/javax.faces.resource/mybootstrap.css.xhtml%3bjsessionid=")||
//                    uri.startsWith(ctx + "/javax.faces.resource/mybootstrap.css.xhtml%3Bjsessionid=")||
//
//                    uri.startsWith(ctx + "/javax.faces.resource/default.css.xhtml;jsessionid=")||
//                    uri.startsWith(ctx + "/javax.faces.resource/default.css.xhtml%3bjsessionid=")||
//                    uri.startsWith(ctx + "/javax.faces.resource/default.css.xhtml%3Bjsessionid=")||
//
//                    uri.startsWith(ctx + "/javax.faces.resource/components.css.xhtml;jsessionid=")||
//                    uri.startsWith(ctx + "/javax.faces.resource/components.css.xhtml%3bjsessionid=")||
//                    uri.startsWith(ctx + "/javax.faces.resource/components.css.xhtml%3Bjsessionid=")||
//
//                    uri.startsWith(ctx + "/javax.faces.resource/jquery/jquery-plugins.js.xhtml;jsessionid=")||
//                    uri.startsWith(ctx + "/javax.faces.resource/jquery/jquery-plugins.js.xhtml%3bjsessionid=")||
//                    uri.startsWith(ctx + "/javax.faces.resource/jquery/jquery-plugins.js.xhtml%3Bjsessionid=")||
//
//                    uri.startsWith(ctx + "/javax.faces.resource/jquery/jquery.js.xhtml;jsessionid=")||
//                    uri.startsWith(ctx + "/javax.faces.resource/jquery/jquery.js.xhtml%3bjsessionid=")||
//                    uri.startsWith(ctx + "/javax.faces.resource/jquery/jquery.js.xhtml%3Bjsessionid=")||
//
//                    uri.startsWith(ctx + "/javax.faces.resource/core.js.xhtml;jsessionid=")||
//                    uri.startsWith(ctx + "/javax.faces.resource/core.js.xhtml%3bjsessionid=")||
//                    uri.startsWith(ctx + "/javax.faces.resource/core.js.xhtml%3Bjsessionid=")||
//
//                    uri.startsWith(ctx + "/javax.faces.resource/extra.js.xhtml;jsessionid=")||
//                    uri.startsWith(ctx + "/javax.faces.resource/extra.js.xhtml%3bjsessionid=")||
//                    uri.startsWith(ctx + "/javax.faces.resource/extra.js.xhtml%3Bjsessionid=")||
//
//                    uri.startsWith(ctx + "/resources/images/logo1.png;jsessionid=")||
//                    uri.startsWith(ctx + "/resources/images/logo1.png%3bjsessionid=")||
//                    uri.startsWith(ctx + "/resources/images/logo1.png%3Bjsessionid=")||
//
//                    uri.startsWith(ctx + "/javax.faces.resource/components.js.xhtml;jsessionid=")||
//                    uri.startsWith(ctx + "/javax.faces.resource/components.js.xhtml%3bjsessionid=")||
//                    uri.startsWith(ctx + "/javax.faces.resource/components.js.xhtml%3Bjsessionid=")||
//
//                    uri.startsWith(ctx + "/resources/images/logo.png;jsessionid=")||
//                    uri.startsWith(ctx + "/resources/images/logo.png%3bjsessionid=")||
//                    uri.startsWith(ctx + "/resources/images/logo.png%3Bjsessionid=")) {
//                return false;
//            }
            return SEMICOLON.stream().anyMatch(uri::contains);
        }
        return false;
src/main/java/org/springframework/web/filter/DelegatingFilterProxy.java
对比新文件
@@ -0,0 +1,409 @@
/*
 * Copyright 2002-2017 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.springframework.web.filter;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
 * Proxy for a standard Servlet Filter, delegating to a Spring-managed bean that
 * implements the Filter interface. Supports a "targetBeanName" filter init-param
 * in {@code web.xml}, specifying the name of the target bean in the Spring
 * application context.
 *
 * <p>{@code web.xml} will usually contain a {@code DelegatingFilterProxy} definition,
 * with the specified {@code filter-name} corresponding to a bean name in
 * Spring's root application context. All calls to the filter proxy will then
 * be delegated to that bean in the Spring context, which is required to implement
 * the standard Servlet Filter interface.
 *
 * <p>This approach is particularly useful for Filter implementation with complex
 * setup needs, allowing to apply the full Spring bean definition machinery to
 * Filter instances. Alternatively, consider standard Filter setup in combination
 * with looking up service beans from the Spring root application context.
 *
 * <p><b>NOTE:</b> The lifecycle methods defined by the Servlet Filter interface
 * will by default <i>not</i> be delegated to the target bean, relying on the
 * Spring application context to manage the lifecycle of that bean. Specifying
 * the "targetFilterLifecycle" filter init-param as "true" will enforce invocation
 * of the {@code Filter.init} and {@code Filter.destroy} lifecycle methods
 * on the target bean, letting the servlet container manage the filter lifecycle.
 *
 * <p>As of Spring 3.1, {@code DelegatingFilterProxy} has been updated to optionally accept
 * constructor parameters when using Servlet 3.0's instance-based filter registration
 * methods, usually in conjunction with Spring 3.1's
 * {@link org.springframework.web.WebApplicationInitializer} SPI. These constructors allow
 * for providing the delegate Filter bean directly, or providing the application context
 * and bean name to fetch, avoiding the need to look up the application context from the
 * ServletContext.
 *
 * <p>This class was originally inspired by Spring Security's {@code FilterToBeanProxy}
 * class, written by Ben Alex.
 *
 * @author Juergen Hoeller
 * @author Sam Brannen
 * @author Chris Beams
 * @since 1.2
 * @see #setTargetBeanName
 * @see #setTargetFilterLifecycle
 * @see Filter#doFilter
 * @see Filter#init
 * @see Filter#destroy
 * @see #DelegatingFilterProxy(Filter)
 * @see #DelegatingFilterProxy(String)
 * @see #DelegatingFilterProxy(String, WebApplicationContext)
 * @see org.springframework.web.WebApplicationInitializer
 */
public class DelegatingFilterProxy extends GenericFilterBean {
    private String contextAttribute;
    private WebApplicationContext webApplicationContext;
    private String targetBeanName;
    private boolean targetFilterLifecycle = false;
    private volatile Filter delegate;
    private final Object delegateMonitor = new Object();
    /**
     * Create a new {@code DelegatingFilterProxy}. For traditional (pre-Servlet 3.0) use
     * in {@code web.xml}.
     * @see #setTargetBeanName(String)
     */
    public DelegatingFilterProxy() {
    }
    /**
     * Create a new {@code DelegatingFilterProxy} with the given {@link Filter} delegate.
     * Bypasses entirely the need for interacting with a Spring application context,
     * specifying the {@linkplain #setTargetBeanName target bean name}, etc.
     * <p>For use in Servlet 3.0+ environments where instance-based registration of
     * filters is supported.
     * @param delegate the {@code Filter} instance that this proxy will delegate to and
     * manage the lifecycle for (must not be {@code null}).
     * @see #doFilter(ServletRequest, ServletResponse, FilterChain)
     * @see #invokeDelegate(Filter, ServletRequest, ServletResponse, FilterChain)
     * @see #destroy()
     * @see #setEnvironment(org.springframework.core.env.Environment)
     */
    public DelegatingFilterProxy(Filter delegate) {
        Assert.notNull(delegate, "Delegate Filter must not be null");
        this.delegate = delegate;
    }
    /**
     * Create a new {@code DelegatingFilterProxy} that will retrieve the named target
     * bean from the Spring {@code WebApplicationContext} found in the {@code ServletContext}
     * (either the 'root' application context or the context named by
     * {@link #setContextAttribute}).
     * <p>For use in Servlet 3.0+ environments where instance-based registration of
     * filters is supported.
     * <p>The target bean must implement the standard Servlet Filter.
     * @param targetBeanName name of the target filter bean to look up in the Spring
     * application context (must not be {@code null}).
     * @see #findWebApplicationContext()
     * @see #setEnvironment(org.springframework.core.env.Environment)
     */
    public DelegatingFilterProxy(String targetBeanName) {
        this(targetBeanName, null);
    }
    /**
     * Create a new {@code DelegatingFilterProxy} that will retrieve the named target
     * bean from the given Spring {@code WebApplicationContext}.
     * <p>For use in Servlet 3.0+ environments where instance-based registration of
     * filters is supported.
     * <p>The target bean must implement the standard Servlet Filter interface.
     * <p>The given {@code WebApplicationContext} may or may not be refreshed when passed
     * in. If it has not, and if the context implements {@link ConfigurableApplicationContext},
     * a {@link ConfigurableApplicationContext#refresh() refresh()} will be attempted before
     * retrieving the named target bean.
     * <p>This proxy's {@code Environment} will be inherited from the given
     * {@code WebApplicationContext}.
     * @param targetBeanName name of the target filter bean in the Spring application
     * context (must not be {@code null}).
     * @param wac the application context from which the target filter will be retrieved;
     * if {@code null}, an application context will be looked up from {@code ServletContext}
     * as a fallback.
     * @see #findWebApplicationContext()
     * @see #setEnvironment(org.springframework.core.env.Environment)
     */
    public DelegatingFilterProxy(String targetBeanName, WebApplicationContext wac) {
        Assert.hasText(targetBeanName, "Target Filter bean name must not be null or empty");
        this.setTargetBeanName(targetBeanName);
        this.webApplicationContext = wac;
        if (wac != null) {
            this.setEnvironment(wac.getEnvironment());
        }
    }
    /**
     * Set the name of the ServletContext attribute which should be used to retrieve the
     * {@link WebApplicationContext} from which to load the delegate {@link Filter} bean.
     */
    public void setContextAttribute(String contextAttribute) {
        this.contextAttribute = contextAttribute;
    }
    /**
     * Return the name of the ServletContext attribute which should be used to retrieve the
     * {@link WebApplicationContext} from which to load the delegate {@link Filter} bean.
     */
    public String getContextAttribute() {
        return this.contextAttribute;
    }
    /**
     * Set the name of the target bean in the Spring application context.
     * The target bean must implement the standard Servlet Filter interface.
     * <p>By default, the {@code filter-name} as specified for the
     * DelegatingFilterProxy in {@code web.xml} will be used.
     */
    public void setTargetBeanName(String targetBeanName) {
        this.targetBeanName = targetBeanName;
    }
    /**
     * Return the name of the target bean in the Spring application context.
     */
    protected String getTargetBeanName() {
        return this.targetBeanName;
    }
    /**
     * Set whether to invoke the {@code Filter.init} and
     * {@code Filter.destroy} lifecycle methods on the target bean.
     * <p>Default is "false"; target beans usually rely on the Spring application
     * context for managing their lifecycle. Setting this flag to "true" means
     * that the servlet container will control the lifecycle of the target
     * Filter, with this proxy delegating the corresponding calls.
     */
    public void setTargetFilterLifecycle(boolean targetFilterLifecycle) {
        this.targetFilterLifecycle = targetFilterLifecycle;
    }
    /**
     * Return whether to invoke the {@code Filter.init} and
     * {@code Filter.destroy} lifecycle methods on the target bean.
     */
    protected boolean isTargetFilterLifecycle() {
        return this.targetFilterLifecycle;
    }
    @Override
    protected void initFilterBean() throws ServletException {
        synchronized (this.delegateMonitor) {
            if (this.delegate == null) {
                // If no target bean name specified, use filter name.
                if (this.targetBeanName == null) {
                    this.targetBeanName = getFilterName();
                }
                // Fetch Spring root application context and initialize the delegate early,
                // if possible. If the root application context will be started after this
                // filter proxy, we'll have to resort to lazy initialization.
                WebApplicationContext wac = findWebApplicationContext();
                if (wac != null) {
                    this.delegate = initDelegate(wac);
                }
            }
        }
    }
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        String referer = ((HttpServletRequest)request).getHeader("Referer");
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append(request.getScheme()).append("://").append(request.getServerName());
        if(referer != null && !referer.equals("") ){
            if(referer.lastIndexOf(String.valueOf(stringBuffer)) != 0){
                HttpServletResponse httpResp1 = (HttpServletResponse)response;
                httpResp1.setStatus(500);
                httpResp1.setContentType("text/html; charset=utf-8");
                httpResp1.getWriter().write("系统不支持当前域名的访问!");
                return;
            }
        }
        String method = ((HttpServletRequest)request).getMethod();
        if (method.toUpperCase().equals("OPTIONS")){
            HttpServletResponse httpResp1 = (HttpServletResponse)response;
            httpResp1.setStatus(500);
            httpResp1.setContentType("text/html; charset=utf-8");
            httpResp1.getWriter().write("系统不支持访问!");
            return;
        }
        String contentType = ((HttpServletRequest)request).getHeader("Content-Type");
        if ((method.toUpperCase().equals("GET") && !StringUtils.isEmpty(contentType) && contentType.contains("form"))||
                (StringUtils.isEmpty(contentType) && method.toUpperCase().equals("POST"))){
            HttpServletResponse httpResp1 = (HttpServletResponse)response;
            httpResp1.setStatus(500);
            httpResp1.setContentType("text/html; charset=utf-8");
            httpResp1.getWriter().write("系统不支持访问!");
            return;
        }
        HttpServletRequest httpReq = (HttpServletRequest) request;
        HttpServletResponse httpRes = (HttpServletResponse) response;
        /**禁止缓存**/
        httpRes.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
        httpRes.setHeader("Pragma", "no-cache");
        httpRes.setHeader("X-Content-Type-Options", "nosniff");
        httpRes.setHeader("X-XSS-Protection", "1");
        httpRes.setHeader("strict-transport-security", "max-age=31536000");
        httpRes.setHeader("X-Frame-Options", "DENY");
        //安全测评需要,如影响使用请注释掉
        if(httpReq.getRequestURI().contains("javax.faces.resource")){
            httpRes.setHeader("Content-Security-Policy", "default-src 'self';script-src 'self';frame-ancestors 'self';");
        }
        // Lazily initialize the delegate if necessary.
        Filter delegateToUse = this.delegate;
        if (delegateToUse == null) {
            synchronized (this.delegateMonitor) {
                delegateToUse = this.delegate;
                if (delegateToUse == null) {
                    WebApplicationContext wac = findWebApplicationContext();
                    if (wac == null) {
                        throw new IllegalStateException("No WebApplicationContext found: " +
                                "no ContextLoaderListener or DispatcherServlet registered?");
                    }
                    delegateToUse = initDelegate(wac);
                }
                this.delegate = delegateToUse;
            }
        }
        // Let the delegate perform the actual doFilter operation.
        invokeDelegate(delegateToUse, request, response, filterChain);
    }
    @Override
    public void destroy() {
        Filter delegateToUse = this.delegate;
        if (delegateToUse != null) {
            destroyDelegate(delegateToUse);
        }
    }
    /**
     * Return the {@code WebApplicationContext} passed in at construction time, if available.
     * Otherwise, attempt to retrieve a {@code WebApplicationContext} from the
     * {@code ServletContext} attribute with the {@linkplain #setContextAttribute
     * configured name} if set. Otherwise look up a {@code WebApplicationContext} under
     * the well-known "root" application context attribute. The
     * {@code WebApplicationContext} must have already been loaded and stored in the
     * {@code ServletContext} before this filter gets initialized (or invoked).
     * <p>Subclasses may override this method to provide a different
     * {@code WebApplicationContext} retrieval strategy.
     * @return the {@code WebApplicationContext} for this proxy, or {@code null} if not found
     * @see #DelegatingFilterProxy(String, WebApplicationContext)
     * @see #getContextAttribute()
     * @see WebApplicationContextUtils#getWebApplicationContext(ServletContext)
     * @see WebApplicationContext#ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE
     */
    protected WebApplicationContext findWebApplicationContext() {
        if (this.webApplicationContext != null) {
            // The user has injected a context at construction time -> use it...
            if (this.webApplicationContext instanceof ConfigurableApplicationContext) {
                ConfigurableApplicationContext cac = (ConfigurableApplicationContext) this.webApplicationContext;
                if (!cac.isActive()) {
                    // The context has not yet been refreshed -> do so before returning it...
                    cac.refresh();
                }
            }
            return this.webApplicationContext;
        }
        String attrName = getContextAttribute();
        if (attrName != null) {
            return WebApplicationContextUtils.getWebApplicationContext(getServletContext(), attrName);
        }
        else {
            return WebApplicationContextUtils.findWebApplicationContext(getServletContext());
        }
    }
    /**
     * Initialize the Filter delegate, defined as bean the given Spring
     * application context.
     * <p>The default implementation fetches the bean from the application context
     * and calls the standard {@code Filter.init} method on it, passing
     * in the FilterConfig of this Filter proxy.
     * @param wac the root application context
     * @return the initialized delegate Filter
     * @throws ServletException if thrown by the Filter
     * @see #getTargetBeanName()
     * @see #isTargetFilterLifecycle()
     * @see #getFilterConfig()
     * @see Filter#init(FilterConfig)
     */
    protected Filter initDelegate(WebApplicationContext wac) throws ServletException {
        Filter delegate = wac.getBean(getTargetBeanName(), Filter.class);
        if (isTargetFilterLifecycle()) {
            delegate.init(getFilterConfig());
        }
        return delegate;
    }
    /**
     * Actually invoke the delegate Filter with the given request and response.
     * @param delegate the delegate Filter
     * @param request the current HTTP request
     * @param response the current HTTP response
     * @param filterChain the current FilterChain
     * @throws ServletException if thrown by the Filter
     * @throws IOException if thrown by the Filter
     */
    protected void invokeDelegate(
            Filter delegate, ServletRequest request, ServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        delegate.doFilter(request, response, filterChain);
    }
    /**
     * Destroy the Filter delegate.
     * Default implementation simply calls {@code Filter.destroy} on it.
     * @param delegate the Filter delegate (never {@code null})
     * @see #isTargetFilterLifecycle()
     * @see Filter#destroy()
     */
    protected void destroyDelegate(Filter delegate) {
        if (isTargetFilterLifecycle()) {
            delegate.destroy();
        }
    }
}
src/main/webapp/WEB-INF/spring-mvc.xml
@@ -17,6 +17,7 @@
    http://www.springframework.org/schema/util/spring-util-2.0.xsd">
    <context:component-scan base-package="com.nanometer.smartlab.api"/>
    <context:component-scan base-package="com.nanometer.smartlab.controller"/>
    <!-- 静态资源(js、image等)的访问 -->
    <mvc:default-servlet-handler/>
@@ -51,6 +52,6 @@
    </bean>
    <mvc:cors>
        <mvc:mapping path="/**" allowed-origins="*" allow-credentials="true" max-age="1800" allowed-methods="GET,POST,OPTIONS"/>
        <mvc:mapping path="/**" allowed-origins="*" allow-credentials="true" max-age="1800" allowed-methods="GET,POST"/>
    </mvc:cors>
</beans>
src/main/webapp/WEB-INF/spring-shiro.xml
@@ -1,10 +1,10 @@
<?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:util="http://www.springframework.org/schema/util"
       xmlns:util="http://www.springframework.org/schema/util" xmlns:cache="http://www.springframework.org/schema/cache"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
       http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
       http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
@@ -60,8 +60,9 @@
    </bean>
    <!-- Cache Manager -->
    <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
    <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
        <property name="cacheManager" ref="ehcacheManager"/>
        <property name="transactionAware" value="true"/>
    </bean>
    <!-- 如果有多个ehcacheManager要在bean加上p:shared="true" -->
@@ -69,9 +70,30 @@
        <property name="configLocation" value="WEB-INF/ehcache.xml"/>
    </bean>
    <!-- cache注解,和spring-redis.xml中的只能使用一个 -->
    <cache:annotation-driven cache-manager="cacheManager" proxy-target-class="true"/>
    <bean id="shiroSpringCacheManager" class="com.nanometer.smartlab.realm.ShiroSpringCacheManager">
        <property name="cacheManager" ref="cacheManager"></property>
    </bean>
    <!--session manager-->
    <bean id="sessionManager"
          class="org.apache.shiro.web.session.mgt.ServletContainerSessionManager">
          class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
        <!-- url上带sessionId 默认为true -->
        <property name="sessionIdUrlRewritingEnabled" value="false"/>
        <property name="sessionDAO" ref="sessionDAO"/>
        <!-- cookie名称 -->
        <property name="sessionIdCookie.name" value="gasid"/>
        <!-- cookie生效路径 -->
        <property name="sessionIdCookie.path" value="/"/>
    </bean>
    <!-- 会话DAO 用于会话的CRUD -->
    <bean id="sessionDAO" class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO">
        <!-- Session缓存名字,默认就是shiro-activeSessionCache -->
        <property name="activeSessionsCacheName" value="activeSessionCache"/>
        <property name="cacheManager" ref="shiroSpringCacheManager"/>
    </bean>
    <!--credentialsMatcher 密码加密-->
@@ -82,9 +104,9 @@
    </bean>
    <!--自定义 Realm-->
    <bean id="authorizationRealm" class="com.nanometer.smartlab.realm.AuthorizationRealm">
        <property name="credentialsMatcher" ref="md5Matcher"/>
    <bean id="authorizationRealm" class="com.nanometer.smartlab.realm.ShiroDbRealm">
        <constructor-arg index="0" name="cacheManager" ref="shiroSpringCacheManager"/>
        <constructor-arg index="1" name="matcher" ref="credentialsMatcher"/>
        <!-- 启用身份验证缓存,即缓存AuthenticationInfo信息,默认false -->
        <property name="authenticationCachingEnabled" value="true"/>
        <!-- 缓存AuthenticationInfo信息的缓存名称 -->
@@ -92,12 +114,21 @@
        <!-- 缓存AuthorizationInfo信息的缓存名称 -->
        <property name="authorizationCacheName" value="authorizationCache"/>
    </bean>
    <!-- 密码错误5次锁定5min -->
    <bean id="credentialsMatcher" class="com.nanometer.smartlab.realm.RetryLimitCredentialsMatcher">
        <constructor-arg ref="shiroSpringCacheManager"/>
        <property name="retryLimitCacheName" value="fivMin"/>
        <!-- 密码加密 1次md5,增强密码可修改此处 -->
        <property name="hashAlgorithmName" value="MD5"/>
        <property name="storedCredentialsHexEncoded" value="true"/>
        <property name="hashIterations" value="1"/>
    </bean>
    <!-- Security Manager -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="authorizationRealm"/>
        <property name="rememberMeManager" ref="rememberMeManager"/>
        <property name="cacheManager" ref="cacheManager"/>
        <property name="cacheManager" ref="shiroSpringCacheManager"/>
        <property name="sessionManager" ref="sessionManager"/>
    </bean>
src/main/webapp/WEB-INF/test/test.properties
@@ -2,10 +2,9 @@
jdbc.username=root
jdbc.password=GKHY@root20201!
#\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD
institute.id = 2
institute.name = \u4E2D\u56FD\u79D1\u5B66\u9662\u82CF\u5DDE\u7EB3\u7C73\u6280\u672F\u4E0E\u7EB3\u7C73\u4EFF\u751F\u7814\u7A76\u6240
institute.url  = http://sinanoaq.com:8050
institute.url  = https://sinanoaq.cn:8002
institute.app.id = wx81a00e3350861b25
institute.app.secret = c307d394875af2cbbe25e01b9e43dcb2
alarm.url = http://sinanoaq.com/daping/sendWarnInfo.json
src/main/webapp/index.xhtml
@@ -41,15 +41,15 @@
                <p:panelGrid columns="1" styleClass="content">
                    <p:outputLabel value="原密码"></p:outputLabel>
                    <p:password value="#{userMngController.oriPassword}" maxlength="100"
                             required="true" requiredMessage="请输入原密码"></p:password>
                             required="true" requiredMessage="请输入原密码" autocomplete="off"></p:password>
                     <p:outputLabel value="新密码(必须是8位以上且包含大小写和特殊字符)"></p:outputLabel>
                     <p:password value="#{userMngController.newPassword}" maxlength="100"
                             required="true" requiredMessage="请输入新密码"></p:password>
                             required="true" requiredMessage="请输入新密码" autocomplete="off"></p:password>
                    <p:outputLabel value="确认密码"></p:outputLabel>
                             <p:password value="#{userMngController.newPasswordSecond}" maxlength="100"
                             required="true" requiredMessage="请输入确认密码"></p:password>
                             required="true" requiredMessage="请输入确认密码" autocomplete="off"></p:password>
                </p:panelGrid>
                <p:panel styleClass="btn">
                    <p:commandButton value="修改" actionListener="#{userMngController.updatePasswordAction}"
@@ -68,15 +68,15 @@
                <p:panelGrid columns="1" styleClass="content">
                    <p:outputLabel value="原密码"></p:outputLabel>
                    <p:password value="#{userMngController.oriPassword}" maxlength="100"
                                required="true" requiredMessage="请输入原密码"></p:password>
                                required="true" requiredMessage="请输入原密码" autocomplete="off"></p:password>
                    <p:outputLabel value="新密码(必须是8位以上且包含大小写和特殊字符)"></p:outputLabel>
                    <p:password value="#{userMngController.newPassword}" maxlength="100"
                                required="true" requiredMessage="请输入新密码"></p:password>
                                required="true" requiredMessage="请输入新密码" autocomplete="off"></p:password>
                    <p:outputLabel value="确认密码"></p:outputLabel>
                    <p:password value="#{userMngController.newPasswordSecond}" maxlength="100"
                                required="true" requiredMessage="请输入确认密码"></p:password>
                                required="true" requiredMessage="请输入确认密码" autocomplete="off"></p:password>
                </p:panelGrid>
                <p:panel styleClass="btn">
                    <p:commandButton value="修改" actionListener="#{userMngController.updatePasswordAction}"
src/main/webapp/login.xhtml
@@ -50,7 +50,7 @@
                    <div>
                        <p:outputLabel value="密码" styleClass="pwd-label"></p:outputLabel>
                        <p:password value="#{loginController.loginPwd}" required="true" requiredMessage="请输入密码"></p:password>
                        <p:password value="#{loginController.loginPwd}" required="true" requiredMessage="请输入密码" autocomplete="off"></p:password>
                    </div>
                    <p:commandButton value="登录" ajax="false" action="#{loginController.login}" styleClass="save-button"></p:commandButton>
                </div>
@@ -59,14 +59,8 @@
    </div>
    <div class="login-footer">
        <!--<p:graphicImage value="/resources/images/logo2.png"></p:graphicImage>-->
            Copyright © 2017  ${institute.name}
            <!--<p:commandLink id="nonAjax" src="http:beian.miit.gov.cn/"   ajax="false">
            <h:outputText value="苏ICP备13012319号-1" />
            </p:commandLink>-->
            <a href="http://beian.miit.gov.cn">苏ICP备10220403号-6</a>
    </div>
</h:body>
</html>
src/main/webapp/user_mng.xhtml
@@ -187,8 +187,7 @@
                <p:outputLabel value="密码" ></p:outputLabel>
                <p:password value="#{userMngController.sysUser.password}" maxlength="100"
                             requiredMessage="请输入密码"
                            ></p:password>
                             requiredMessage="请输入密码" autocomplete="off"></p:password>
                <p:outputLabel value="电话"></p:outputLabel>
                <p:inputText value="#{userMngController.sysUser.phone}" maxlength="30"></p:inputText>