LoginAction.java

/*
 *        @ Copyright 2001 FA Software;
 *        All right reserved. No part of this program may be reproduced or
 *        transmitted in any form or by any means, electronic or
 *        mechanical, including photocopying, recording, or by any
 *        information storage or retrieval system without written
 *        permission from FA Software, except for inclusion of brief
 *        quotations in a review.
 */
package com.mycim.webapp.actions.security;

import com.fa.sesa.exception.Assert;
import com.fa.sesa.exception.Errors;
import com.fa.sesa.i18n.I18nUtils;
import com.fa.sesa.threadlocal.LocalContext;
import com.mycim.framework.context.spring.SpringContext;
import com.mycim.framework.logging.Logger;
import com.mycim.framework.logging.LoggerFactory;
import com.mycim.framework.utils.lang.BooleanUtils;
import com.mycim.framework.utils.lang.ObjectUtils;
import com.mycim.framework.utils.lang.StringUtils;
import com.mycim.framework.utils.lang.collections.CollectionUtils;
import com.mycim.framework.utils.lang.collections.MapUtils;
import com.mycim.framework.utils.lang.time.DateUtils;
import com.mycim.framework.utils.msg.JsonUtils;
import com.mycim.server.security.service.SecurityService;
import com.mycim.valueobject.MessageIdList;
import com.mycim.valueobject.ObjectList;
import com.mycim.valueobject.SystemConstant;
import com.mycim.valueobject.bas.NamedObject;
import com.mycim.valueobject.bas.Relation;
import com.mycim.valueobject.consts.LinkTypeList;
import com.mycim.valueobject.consts.ReferenceDetailNames;
import com.mycim.valueobject.consts.SessionNames;
import com.mycim.valueobject.security.LoginLog;
import com.mycim.valueobject.security.Role;
import com.mycim.valueobject.security.User;
import com.mycim.valueobject.security.UserGroup;
import com.mycim.valueobject.sys.Facility;
import com.mycim.valueobject.sys.ReferenceFileDetail;
import com.mycim.webapp.Constants;
import com.mycim.webapp.WebContext;
import com.mycim.webapp.WebUtils;
import com.mycim.webapp.actions.AbstractAction;
import com.mycim.webapp.forms.security.LoginForm;
import com.mycim.webapp.secutiry.jwt.JwtUtils;
import com.mycim.webapp.secutiry.jwt.token.JwtToken;
import com.mycim.webapp.utils.LdapHelper;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;

public final class LoginAction extends AbstractAction {

    /**
     * seeionId和用户的绑定关系
     */
    public static final Map<String, String> SESSIONID_USER = new HashMap<String, String>();

    private static final Logger LOGGER = LoggerFactory.getLogger(LoginAction.class);

    private SecurityService securityService = SpringContext.getBean(SecurityService.class);


    @Override
    public ActionForward init(ActionMapping mapping, ActionForm form, HttpServletRequest request,
                              HttpServletResponse response) {

        String unified = request.getParameter("unified");
        String ldap = request.getParameter("ldap");
        if (StringUtils.isNotBlank(unified)) {
            return mapping.findForward("unified");
        }

        // 增加验证,如果token在有效期,默认为已登陆
        try {
            if (JwtUtils.verify(new JwtToken(JwtUtils.getToken(request)))) {
                return main(mapping, request, response);
            }
        } catch (Exception e) {
            LOGGER.error("Token Login Error!");
        }
        return mapping.getInputForward();
    }

    /**
     * 重定向到main页面
     *
     * @param response
     * @return
     */
    public ActionForward main(ActionMapping mapping, HttpServletRequest request,
                              HttpServletResponse response) throws Exception {
        String userId = JwtUtils.getUserId(request);
        long facilityRrn = JwtUtils.getFacilityRrn(request);

        User user = securityService
                .getUser(new User(userId, getNamedSpace(ObjectList.USER_KEY, facilityRrn), ObjectList.USER_KEY));

        if (isNeedModifyPassword(user)) {
            request.setAttribute("UserId", userId);
            return mapping.findForward("modifyPassword");
        } else {
            response.sendRedirect("portal.do");
        }
        return WebUtils.NULLActionForward;
    }

    /**
     * 登出<br> 清除session中的数据,重定向到login页面
     *
     * @param request
     * @param response
     * @return
     */
    public ActionForward logout(HttpServletRequest request, HttpServletResponse response) throws Exception {
        JwtUtils.setTokenToCookie(response, null);
        String loginFlag = request.getParameter("loginFlag");
        if (StringUtils.equalsIgnoreCase("unifiedLogin", loginFlag)) {
            response.sendRedirect(request.getContextPath() + "/login.do?unified=1");
        } else {
            response.sendRedirect(request.getContextPath() + "/login.do");
        }
        return WebUtils.NULLActionForward;
    }

    /**
     * 修改密码
     *
     * @return Response returns a JSON format string
     */
    public String changePassword(Map map) {
        String oldPassword = MapUtils.getString(map, "oldpassword");
        String newPassWord = MapUtils.getString(map, "newpassword");

        String result;
        checkAndUpdatePassword(LocalContext.getUserRrn(), oldPassword, newPassWord);

        return I18nUtils.getMessage(MessageIdList.USER_PWD_UPDATE_SUCCESS, "密码修改成功!");
    }

    /**
     * 获取系统运行模式的标签信息
     *
     * @return Response returns a JSON format string
     */
    public Map<String, Object> getRunModel(HttpServletRequest request) {
        Map<String, Object> data = new HashMap<>();
        String label = I18nUtils.getLabel("LBS_RUNNING_MODE");
        data.put("runModel", label);

        // List<String> prodURLs = sysService.getRefData1Values("$$PRODUCTION_ENV_URL");
        // List<String> testURLs = sysService.getRefData1Values("$$TEST_ENV_URL");
        //
        // if (prodURLs != null && prodURLs.contains(request.getServerName())) {
        //     data.put("prodMES", true);
        // }
        //
        // if (testURLs != null && testURLs.contains(request.getServerName())) {
        //     data.put("testMES", true);
        // }
        return data;
    }

    /**
     * main页面,获取当前登陆用户信息
     *
     * @return Response returns a JSON format string
     */
    public Map<String, Object> getLoginUserInfo() {
        User userInfo = securityService.getUser(LocalContext.getUserRrn());
        Assert.isFalse(userInfo == null,
                       Errors.create().key(MessageIdList.USER_NOT_FOUND).content("没有获取用户信息,请检查!").build());

        String relaseVersionInform = WebContext.getRelaseVersionInform();
        boolean informFlag = false;
        if(StringUtils.equalsIgnoreCase(relaseVersionInform, SystemConstant.Str.ON)){
            informFlag = true;
        }
        Map<String, Object> data = new HashMap<>();

        data.put("informFlag", informFlag);
        data.put("username", userInfo.getUserName());
        data.put("userRrn", userInfo.getInstanceRrn());
        data.put("instanceId", userInfo.getInstanceId());

        return data;
    }

    /**
     * LDAP登陆
     *
     * @param request
     * @param response
     * @return Response returns a JSON format string, then redirect To Main(action=main)
     */
    public Map<String, Object> Login(LoginForm theForm, HttpServletRequest request, HttpServletResponse response) {
        Map<String, Object> result = new HashMap(2);
        long facilityRrn = theForm.getFacility();
        String inputUserId = theForm.getUsername();
        String userId = inputUserId.toUpperCase();
        String _password = theForm.getPassword();
        String language = theForm.getLanguage();

        String password = StringUtils.encodeByMD5(_password);
        LoginLog loginlog = new LoginLog();
        loginlog.setUserName(userId);
        loginlog.setLanguage(language);
        loginlog.setFacilityRrn(facilityRrn);
        loginlog.setSource("MES");
        loginlog.setLoginIp(getIpAddress(request));
        loginlog.setBrowserInfo(request.getHeader("user-agent"));

        User user = securityService
                .getUser(new User(userId, getNamedSpace(ObjectList.USER_KEY, facilityRrn), ObjectList.USER_KEY));

        //TODO :  ldap逻辑需要重构,使用spring ldap
        //先走ldap判断用户 若失败再通过mes判断。
        //        Map<String, Object> authenticationInfo = sysService.getLoginAuthenticationInfo(facilityRrn);
        //        //aString auType = MapUtils.getString(authenticationInfo, "authenticationType");
        // 如果是2的话代表开启ldap 现在不采用
        //        String errorMsg = LdapHelper.authenticate(inputUserId, _password, authenticationInfo);
        //        if(StringUtils.isNotEmpty(errorMsg)){
        //ldap认证失败。走mes
        validateLoginInfo(facilityRrn, userId, password);
        //        }else{
        //            //如果是ldapId登陆,通过ldapId查询user信息
        //            user = securityService.getUserByLdapId(inputUserId);
        //        }

        Facility facility = sysService.getFacility(facilityRrn);

        String specialDataPermissionRoles = getSpecialDataPermissionRoles();
        Collection<Role> roleList = securityService.getUserRoleListWithGroupGrant(user.getInstanceRrn());

        boolean specialRole = checkSpecialRole(roleList, specialDataPermissionRoles);

        securityService.checkUserTime(user.getInstanceRrn(), facility.getInstanceRrn());

        LOGGER.info("Login Facility: {}, User: {}", facility.getInstanceId(), user.getInstanceId());


        loginlog.setUserRrn(user.getInstanceRrn());
        loginlog.setResInfo("SUCCESS");

        // String processRrns = getProcessRrns(user.getInstanceRrn());
        String dataPermissionFlag = sysService.getDataPermissionFlag(facilityRrn);
        // token 设置到 cookie
        JwtToken jwtToken = new JwtToken(facilityRrn, user.getInstanceRrn(), user.getInstanceId(), language,
                                         StringUtils.EMPTY, dataPermissionFlag);
        jwtToken.setNeedUpdatePwd(isNeedModifyPassword(user));//jwt塞个需要修改密码的拦截
        jwtToken.setSpecialRole(specialRole);
        JwtUtils.setTokenToCookie(response, JwtUtils.sign(jwtToken));

        // 添加sessionId和用户的绑定
        securityService.insertLoginLog(loginlog);

        //回传参数
        result.put(SessionNames.USER_KEY, user.getInstanceId());
        result.put(SessionNames.FACILITY_KEY, facilityRrn);
        //        result.put("profiles", WebContext.getActiveProfile().toUpperCase());
        return result;
    }

    private boolean checkSpecialRole(Collection<Role> roleList, String specialDataPermissionRoles) {
        boolean specialRole = false;
        if (StringUtils.isNotBlank(specialDataPermissionRoles) && CollectionUtils.isNotEmpty(roleList)){
            for (Role role:roleList){
                String roleId = role.getInstanceId();
                if (!StringUtils.equalsIgnoreCase("N/A", roleId)) {
                    if (StringUtils.contains(specialDataPermissionRoles, StringUtils.COMMA_SIGN + roleId + StringUtils.COMMA_SIGN)){
                        specialRole = true;
                    }
                }
            }
        }
        return specialRole;
    }

    private String getSpecialDataPermissionRoles() {
        ReferenceFileDetail pcdNameDetail = new ReferenceFileDetail(ReferenceDetailNames.SPECIAL_DATA_PERMISSION,
                                                                    getNamedSpace(ObjectList.REFERENCE_FILE_KEY, LocalContext.getFacilityRrn()), ObjectList.REFERENCE_FILE_KEY);

        pcdNameDetail.setKey1Value("SPECIAL_ROLE");
        pcdNameDetail.setKey2Value(SystemConstant.Str.BLANK);
        pcdNameDetail = sysService.getReferenceFileDetail(pcdNameDetail);
        if (pcdNameDetail == null || StringUtils.isBlank(pcdNameDetail.getData1Value())){//没有配置这种类型的 NamingRule
            return StringUtils.EMPTY;
        }

        return StringUtils.COMMA_SIGN + pcdNameDetail.getData1Value() + StringUtils.COMMA_SIGN;
    }


    /**
     * 来自其他地址的跨域请求
     *
     * @author zhi.cai
     * @date 2020/4/29
     * @since 1.8
     **/
    public String unifiedLogin(HttpServletRequest request, HttpServletResponse response) {
        Map<String, Object> result = new HashMap(2);
        String inputUserId = request.getParameter("username");
        String userId = inputUserId.toUpperCase();
        String _password = request.getParameter("password");
        String language = request.getParameter("language");
        long facilityRrn = Long.parseLong(request.getParameter("facility"));
        String callback = request.getParameter("callback");
        String password = StringUtils.encodeByMD5(_password);
        LoginLog loginlog = new LoginLog();
        loginlog.setUserName(userId);
        loginlog.setLanguage(language);
        loginlog.setFacilityRrn(facilityRrn);
        loginlog.setSource("MES");
        loginlog.setLoginIp(getIpAddress(request));
        loginlog.setBrowserInfo(request.getHeader("user-agent"));

        User user = securityService
                .getUser(new User(userId, getNamedSpace(ObjectList.USER_KEY, facilityRrn), ObjectList.USER_KEY));
        try {
            //先走ldap判断用户 若失败再通过mes判断。
            Map<String, Object> authenticationInfo = sysService.getLoginAuthenticationInfo(facilityRrn);
            //aString auType = MapUtils.getString(authenticationInfo, "authenticationType");
            // 如果是2的话代表开启ldap 现在不采用
            String errorMsg = LdapHelper.authenticate(inputUserId, _password, authenticationInfo);
            if (StringUtils.isNotEmpty(errorMsg)) {
                //ldap认证失败。走mes
                validateLoginInfo(facilityRrn, userId, password);
            } else {
                //如果是ldapId登陆,通过ldapId查询user信息
                user = securityService.getUserByLdapId(inputUserId);
            }
        } catch (Exception e) {
            result.put("success", "false");
            if ("EN".equalsIgnoreCase(language)) {
                result.put("msg", "Wrong username or password!");
            } else {
                result.put("msg", "用户名或密码错误!");
            }
            String resultJson = JsonUtils.toString(result);
            try {
                response.getWriter().write(callback + "('" + resultJson + "')");
            } catch (IOException ex) {
                LOGGER.error(ex);
            }
            return null;
        }

        Facility facility = sysService.getFacility(facilityRrn);

        String specialDataPermissionRoles = getSpecialDataPermissionRoles();
        Collection<Role> roleList = securityService.getUserRoleListWithGroupGrant(user.getInstanceRrn());

        boolean specialRole = checkSpecialRole(roleList, specialDataPermissionRoles);

        securityService.checkUserTime(user.getInstanceRrn(), facility.getInstanceRrn());

        LOGGER.info("Login Facility: {}, User: {}", facility.getInstanceId(), user.getInstanceId());


        loginlog.setUserRrn(user.getInstanceRrn());
        loginlog.setResInfo("SUCCESS");

        // String processRrns = getProcessRrns(user.getInstanceRrn());
        String dataPermissionFlag = sysService.getDataPermissionFlag(facilityRrn);
        // token 设置到 cookie
        JwtToken jwtToken = new JwtToken(facilityRrn, user.getInstanceRrn(), user.getInstanceId(), language,
                                         StringUtils.EMPTY, dataPermissionFlag);
        jwtToken.setSpecialRole(specialRole);
        JwtUtils.setTokenToCookie(response, JwtUtils.sign(jwtToken));

        // 添加sessionId和用户的绑定
        securityService.insertLoginLog(loginlog);

        //回传参数
        result.put(SessionNames.USER_KEY, user.getInstanceId());
        result.put(SessionNames.FACILITY_KEY, facilityRrn);
        //result.put("profiles", WebContext.getActiveProfile().toUpperCase());

        try {
            String resultJson = JsonUtils.toString(result);
            response.getWriter().write(callback + "('" + resultJson + "')");
        } catch (IOException e) {
            LOGGER.error(e);
        }
        return null;
    }


    public String checkPwd(String pwd) {
        String userId = LocalContext.getUserId();
        Long facilityRrn = LocalContext.getFacilityRrn();
        String pwd_md5 = StringUtils.encodeByMD5(pwd);
        String language = I18nUtils.getCurrentLanguage().name();
        User user = securityService.getUser(userId, facilityRrn);
        String ldapId = user.getLdapId();
        String errorMsg = "";
        Map<String, Object> authenticationInfo = sysService.getLoginAuthenticationInfo(facilityRrn);
        if (StringUtils.isNotEmpty(ldapId)) {
            errorMsg = LdapHelper.authenticate(user.getLdapId(), pwd, authenticationInfo);
        }

        if (StringUtils.isEmpty(ldapId) || StringUtils.isNotEmpty(errorMsg)) {
            //ldap验证异常
            Long userRrn = securityService.checkPassword(userId, pwd_md5, facilityRrn);
            Assert.isFalse(null == userRrn || userRrn.longValue() <= 0,
                           Errors.create().key(MessageIdList.LOGIN_PASSWORD_NOT_CORRECT).content("密码不正确").build());
        }
        return null;
    }

    /**
     * 登陆界面获取FAB选项
     *
     * @return Response returns a JSON format string
     */
    public List<Map> getFacilitys() {
        return sysService.getAllFacility();
    }


    public Map<String, Map<String, Map>> getLabInfo() {
        List<Map> unifedLogin = sysService.getLabInfo();
        Map<String, Map> uatMap = new HashMap<>();
        Map<String, Map> productionMap = new HashMap<>();

        for (Map map : unifedLogin) {
            String profiles = MapUtils.getString(map, "PROFILES");
            String labId = MapUtils.getString(map, "LAB_ID");
            String facility = MapUtils.getString(map, "FACILITY");
            String url = MapUtils.getString(map, "URL");
            Map secondary = new HashMap();
            secondary.put("facility", facility);
            secondary.put("url", url);
            if ("uat".equalsIgnoreCase(profiles)) {
                uatMap.put(labId, secondary);
            } else if ("production".equalsIgnoreCase(profiles)) {
                productionMap.put(labId, secondary);
            }
        }
        Map<String, Map<String, Map>> result = new HashMap();
        result.put("production", productionMap);
        result.put("uat", uatMap);
        return result;
    }

    /**
     * 跨域登录过来中转,页面存储localStorage
     *
     * @param mapping
     * @param request
     * @param response
     * @return
     */
    public ActionForward transferLogin(ActionMapping mapping, HttpServletRequest request,
                                       HttpServletResponse response) {
        String facilityId = request.getParameter("facilityId");
        String userId = JwtUtils.getUserId(request);
        long facilityRrn = JwtUtils.getFacilityRrn(request);
        String language = JwtUtils.getLanguage(request);
        List<Map> versionList = sysService.getAllFacilityVersion();
        String versionStr = "";
        for (Map map : versionList) {
            versionStr = MapUtils.getString(map, "SYSTEM_VERSION");
        }

        request.setAttribute("facilityId", facilityId);
        request.setAttribute("version", versionStr);
        request.setAttribute("username", userId);
        request.setAttribute("facility", facilityRrn);
        request.setAttribute("language", language);
        return mapping.findForward("transferLogin");
    }

    /**
     * 获取 当前系统环境
     *
     * @return
     */
    public Map<String, Object> getProfile() {
        String profile = WebContext.getActiveProfile().toUpperCase();
        String version = WebContext.getVersion();
        String color = sysService.getReferenceFileData1ValueByKey1Value("$$PROFILE_ENV", profile);
        if (StringUtils.isEqual(profile, color) || Objects.isNull(color)) {
            color = "rgb(51, 97, 147)";
        }

        Map<String, Object> result = new HashMap<>();
        result.put("profile", profile);
        result.put("color", color);
        result.put("version",version);
        return result;
    }

    public List<Map> getVersion() {
        return sysService.getAllFacilityVersion();
    }

    /**
     * 判断当前用户是否需要修改密码<br> 1. 首次登陆密码是否过期<br> 2. 上次修改密码时间是否无效
     *
     * @param user
     * @return
     */
    private boolean isNeedModifyPassword(User user) {
        return isExpiredFirstLoginPassword(user) || isInvalidLastChangePasswordTime(user);
    }

    /**
     * 判断上次修改密码时间是否无效
     *
     * @param user
     * @return
     */
    private boolean isInvalidLastChangePasswordTime(User user) {
        long lastChangePwdTime = securityService.getUserLastChangePasswordTime(user.getInstanceRrn());
        if (lastChangePwdTime > 0) {
            Date date = new Date(DateUtils.addTimeByUnit(lastChangePwdTime, "M", 3L));
            // PasswordModifiedTime + 3 Month > Current Time -> 每3个月修改一次密码
            return DateUtils.compareDateWithNow(date) == -1;
        }
        return false;
    }

    /**
     * 首次登陆密码是否过期
     *
     * @param user
     * @return
     */
    private boolean isExpiredFirstLoginPassword(User user) {
        return user.getLastLoginTime() == null && StringUtils.equals(user.getFirstLoginPasswordExpired(), "1");
    }

    /**
     * 验证后更新密码
     *
     * @param userRrn
     * @param oldPassword
     * @param newPassWord
     */
    private void checkAndUpdatePassword(long userRrn, String oldPassword, String newPassWord) {
        Assert.isFalse(StringUtils.isEmpty(oldPassword) || StringUtils.isEmpty(newPassWord),
                       Errors.create().key(MessageIdList.LOGIN_OLD_NEW_PWD_NULL).content("原密码或新密码不能为空!").build());
        boolean isPasswordCorrect = securityService.checkPassword(userRrn, StringUtils.encodeByMD5(oldPassword));
        Assert.isTrue(isPasswordCorrect,
                      Errors.create().key(MessageIdList.LOGIN_OLD_PWD_NULL).content("原密码不正确,请确认!").build());
        boolean isPasswordUpdated = securityService.updatePassword(userRrn, StringUtils.encodeByMD5(newPassWord));
        Assert.isTrue(isPasswordUpdated,
                      Errors.create().key(MessageIdList.LOGIN_PWD_UPDATE_FAIL).content("密码修改失败,请联系管理员!").build());
    }

    /**
     * 验证登陆信息
     *
     * @param facilityRrn
     * @param userId
     * @param password
     */
    private void validateLoginInfo(Long facilityRrn, String userId, String password) {
        String errorMsg = null;

        long userRrn = securityService.validUser(userId, password, facilityRrn);
        if (userRrn == 0) {
            errorMsg = I18nUtils.getMessage(MessageIdList.LOGIN_MISSING_USER, "用户不存在,请检查");
        } else if (userRrn == -1) {
            errorMsg = I18nUtils.getMessage(MessageIdList.LOGIN_PASSWORD_NOT_CORRECT, "密码不正确");

        } else if (isLockedUser(facilityRrn, userId, userRrn)) {
            errorMsg = I18nUtils.getMessage(MessageIdList.LOGIN_USER_LOCKED, "用户{}已被锁定,请联系系统管理员", userId);
        }

        Assert.isFalse(StringUtils.isNotEmpty(errorMsg), Errors.create().content(errorMsg).build());
    }

    /**
     * 是否是LOCKED状态用户<br> 1. 当前用户是否在NO_ENTER用户组中<br> 2. 最后登陆时间是否无效
     *
     * @param facilityRrn
     * @param userRrn
     * @return
     */
    private boolean isLockedUser(Long facilityRrn, String userId, long userRrn) {
        long noEnterUserGroupRrn = getInstanceRrn(Constants.NO_ENTER_KEY, facilityRrn, ObjectList.USERGROUP_KEY);
        // 只有在数据库中存在NO_ENTER用户组的情况下才能正确检查到用户和用户组的关系
        if (noEnterUserGroupRrn == 0) {
            return false;
        }
        Relation relation = baseService.getRelation(userRrn, noEnterUserGroupRrn);
        return relation != null || isInvalidLastLoginTime(facilityRrn, userId, userRrn);
    }

    /**
     * 判断最后登陆时间是否无效<br> 如无效,当前用户将变更状态为Locked并被添加到NO_ENTER用户组中
     *
     * @param facilityRrn
     * @param userId
     * @param userRrn
     * @return
     */
    private boolean isInvalidLastLoginTime(Long facilityRrn, String userId, long userRrn) {
        long lastLoginTime = securityService.getUserLastLoginTime(userRrn);
        if (lastLoginTime > 0) {
            // LastLoginTime + 3 Month > Current Time -> 3个月没有登陆过就锁定账户
            Date date = new Date(DateUtils.addTimeByUnit(lastLoginTime, "M", 3L));
            if (DateUtils.compareDateWithNow(date) == -1) {
                // lock user
                this.addUserToUserGroup(userId, facilityRrn);
                securityService.changeUserStatus(userRrn, Constants.LOCKED_KEY, userId);

                // update user last login time
                securityService.checkUserTime(userRrn, facilityRrn);
                return true;
            }
        }
        return false;
    }

    /**
     * 添加用户至NO_ENTER用户组中
     *
     * @param userId
     * @param facilityRrn
     */
    private void addUserToUserGroup(String userId, Long facilityRrn) {
        UserGroup userGroup = new UserGroup(Constants.NO_ENTER_KEY,
                                            baseService.getNamedSpace(facilityRrn, ObjectList.USERGROUP_KEY),
                                            ObjectList.USERGROUP_KEY);
        userGroup = securityService.getUserGroup(userGroup);

        User fromUser = new User(userId, baseService.getNamedSpace(facilityRrn, ObjectList.USER_KEY),
                                 ObjectList.USER_KEY);
        fromUser = securityService.getUser(fromUser);
        Relation userToGroupRelation = this.buildRelation(fromUser, userGroup);
        userToGroupRelation.setInstanceId(userId);
        userToGroupRelation.setNamedSpace(baseService.getNamedSpace(facilityRrn, ObjectList.USER_KEY));
        userToGroupRelation.setObject(ObjectList.USER_KEY);

        securityService.addUserToUsergroup(userToGroupRelation);
    }

    /**
     * 构建系统对象的关联关系
     *
     * @param fromObject
     * @param toObject
     * @return
     * @throws ServletException
     */
    private Relation buildRelation(NamedObject fromObject, NamedObject toObject) {
        Relation relation = new Relation();

        if (fromObject.getInstanceRrn() <= 0) {
            long fromRrn = baseService.getNamedObjectRrn(fromObject);

            if (fromRrn > 0) {
                relation.setFromRrn(fromRrn);
            } else {
                return null;
            }
        } else {
            relation.setFromRrn(fromObject.getInstanceRrn());
        }

        if (toObject.getInstanceRrn() <= 0) {
            long toRrn = baseService.getNamedObjectRrn(toObject);

            if (toRrn > 0) {
                relation.setToRrn(toRrn);
            } else {
                return null;
            }
        } else {
            relation.setToRrn(toObject.getInstanceRrn());
        }

        return relation;
    }

    private String getProcessRrns(long userRrn) {
        Set<Long> processRrns = new HashSet<>();
        List<UserGroup> userGroups = securityService.getUserGroupByUserRrn(userRrn);
        for (UserGroup userGroup : userGroups) {
            List<Relation> relations = baseService
                    .getRelationsUseToRrn(userGroup.getInstanceRrn(), LinkTypeList.PROCESS_TO_PERMISSIONS_GROUP);
            for (Relation relation : relations) {
                processRrns.add(relation.getFromRrn());
            }
        }
        return StringUtils.join(processRrns, ",");
    }

}