wangting
2024-12-26 fa261e8c1220b31af54e8167e4de9c3320b1af27
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
package com.vci.client.logon.base;
 
import java.text.MessageFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
 
import com.vci.client.ClientSession;
import com.vci.client.common.objects.ClientInfo;
import com.vci.client.common.objects.UserEntityObject;
import com.vci.client.common.objects.UserLogonObject;
import com.vci.client.common.objects.UserObject;
import com.vci.client.framework.appConfig.object.AppConfigDetailObject;
import com.vci.client.framework.delegate.AppConfigDetailClientDelegate;
import com.vci.client.framework.delegate.RightManagementClientDelegate;
import com.vci.client.framework.systemConfig.object.CombinationObject;
import com.vci.client.framework.systemConfig.object.CombinationValueObject;
import com.vci.client.framework.systemConfig.object.PasswordStrategyObject;
import com.vci.client.framework.util.RightControlUtil;
import com.vci.client.ui.exception.VCIException;
import com.vci.client.ui.locale.LocaleDisplay;
import com.vci.client.ui.swing.VCIOptionPane;
import com.vci.corba.common.VCIError;
import com.vci.corba.framework.data.DataSourceInfo;
import com.vci.mw.ClientContextVariable;
 
/**
 * 通用的用户登录处理逻辑
 * 
 * <p>Title: </p>
 * <p>Description: </p>
 * <p>Copyright: Copyright (c) 2016</p>
 * <p>Company: VCI</p>
 * @author xiongchao
 * @time 2017-1-12
 * @version 1.0
 */
public class LogonHandler {
    
    private RightManagementClientDelegate rmcd = new RightManagementClientDelegate();
 
    private int defaultWrongNum = 5;
    private int defaultLogonTime = 30;
    private int dafaultOverdueDay = 30;
    private int dafaultRemideDay = 5;
    
 
    private String getI18n(String key){
        return LocaleDisplay.getI18nString(key, "RMIPFramework", Locale.getDefault());
    }
    private String getThisI18n(String key){
        return getI18n(getClass().getSimpleName() + "." + key);
    }
    public LogonResult checkLogin(String userName, String passWord, String clientIP) throws VCIError, VCIException {
        return checkLogin(userName, passWord, clientIP, true);
    }
    
    public LogonResult checkLogin(String userName, String passWord, String clientIP, boolean pwdStagVerify) throws VCIError, VCIException {
        return checkLogin(userName, passWord, clientIP, pwdStagVerify, false);
    }
    public LogonResult checkLoginForBS(String userName, String passWord, String clientIP, boolean pwdStagVerify) throws VCIError, VCIException {
        return checkLogin(userName, passWord, clientIP, pwdStagVerify, true);
    }
    protected LogonResult checkLogin(String userName, String passWord, String clientIP, boolean pwdStagVerify, boolean forBS) throws VCIError, VCIException {
        
        rmcd = new RightManagementClientDelegate(getUserEntityObject(userName, clientIP));
        
        LogonResult res = new LogonResult();
        // 已存在用户
        UserObject existUserObj = getUserObjToLock(userName);
        if("".equals(existUserObj.getId())){
            // 用户名不存在
            return new LogonResult(false, getThisI18n("userNameNotExists"));
        }
        // 已存在用户的登录信息
        UserLogonObject userLogonObj = getUserLogonObj(existUserObj.getId());
        
        PasswordStrategyObject pwdStgObj = null;
        if(pwdStagVerify){
            // 用户的密码策略默认密码策略
            if (!(RightControlUtil.isAdminOrDeveloperOrRoot(userName))) {
                pwdStgObj = rmcd.fetchPasswordStrategyByUserId(existUserObj.getId());
            }
        }
        
        // 没有密码策略的场景
        if(pwdStgObj == null || "".equals(pwdStgObj.getId())){
            // 没有密码策略时的登录认证逻辑
            UserObject userObj = checkLoginToSystem(userName, passWord, clientIP);
            if(userObj == null){
                // 用户名或密码错误
                return new LogonResult(false, getThisI18n("userNameOrPwdWrong"));
            } 
            // 登录成功
            res.setSuccess(true);
            res.setMessage("");
            res.setLogonedUserObject(userObj);
            // add by xchao 2017.12.13 begin 
            // 在登录结果中加入当前登录用户所代表的VCIInvationInfo对象
            res.setInvocationInfo(rmcd.getLogonedUserInvocationInfo(userObj, getClientInfo(clientIP), forBS));
            // add by xchao 2017.12.13 end 
        } else {
            // 有密码策略的登录校验场景
            res  = checkLogiForNoPwdStage(userName, passWord, clientIP, existUserObj, userLogonObj, pwdStgObj, forBS);
        }
        
        LogonResult ipChkRes = checkUserIPSecetIsOk(userName);
        if(ipChkRes != null){
            res = ipChkRes;
        }
        return res;
    }
    
    private LogonResult checkUserIPSecetIsOk(String userName) throws VCIException{
        AppConfigDetailClientDelegate delegate = new AppConfigDetailClientDelegate(rmcd.getUserEntityObject());
        AppConfigDetailObject ipConfigDetail = delegate.getAppConfigDetailByKey("ipSecuritySwitch");
        AppConfigDetailObject userConfigDetail = delegate.getAppConfigDetailByKey("userSecuritySwith");
        String machineSwitch = ipConfigDetail.getValue();//value值为on时代表机器密级开启,值为其他或者不配置时代表不开启。
        String userSwitch = userConfigDetail.getValue();//value值为on时代表用户密级开启,值为其他或者不配置时代表不开启。
        if(machineSwitch.equals("on") && userSwitch.equals("on")){
            String machineValue = ClientContextVariable.getVariablebyKey(userName, "CURRENTMACHINE.SECRET");//机器密级
            String userValue = ClientContextVariable.getUserInvocation(userName).secretGrade;//用户密级
            if(Integer.parseInt(userValue) < Integer.parseInt(machineValue)){
                // 用户密级与机器密级不匹配,登录失败!
                return new LogonResult(false, getThisI18n("userSecretNotMatchMachineSecret"));
            }
        }
        return null;
    }
    
    
    /**
     * 
     * @param userName
     * @param passWord
     * @param existUserObj
     * @param userLogonObj
     * @param pwdStgObj
     * @return
     * @throws VCIException 
     */
    private LogonResult checkLogiForNoPwdStage(
            String userName, String passWord, String clientIP, 
            UserObject existUserObj,
            UserLogonObject userLogonObj,
            PasswordStrategyObject pwdStgObj, boolean forBS) throws VCIError, VCIException {
        LogonResult res = new LogonResult();
        
        // 有密码策略的场景
        defaultWrongNum = pwdStgObj.getRetryTime(); // 获取密码策略规定的错误登录次数
        defaultLogonTime = pwdStgObj.getLockTime(); // 获取密码策略规定的锁定时间
        dafaultOverdueDay = pwdStgObj.getOverdueDay(); // 获取密码规则的过期天数
        dafaultRemideDay = pwdStgObj.getRemideDay(); // 获取密码策略规定的密码快过期提醒天数(提前xx天开始提醒该修改密码)
        
        // 取出最后一次的登录信息
        // 如果在 锁定时间范围内密码错误次数已经超出密码策略限制
        // 则给出用户已锁定的提示
        int wrongNum = userLogonObj.getPlWrongNum();
        long lastLogonTime = userLogonObj.getPlLogonTime() + 1;
        long systemTime = 0;
        systemTime = rmcd.getSystemTime();
        int timeGap = compare_time(lastLogonTime, systemTime, true);
        if(wrongNum > 0 && wrongNum >= defaultWrongNum && timeGap < defaultLogonTime) {
            // 在锁定时间范围内,密码错误次数已经超出了密码策略所允许的最大值,
            // 此时直接给出 用户已被锁定的提示
            int remainTime = defaultLogonTime - timeGap;
            // "该用户已被锁定,请等" + remainTime + "分钟之后再尝试登录,或找管理员解锁!")
            return new LogonResult(false, MessageFormat.format(getThisI18n("userIsLockedPleaseWaitSomeTimeToTry"), remainTime));
        }
        
        // 按正常的用户认证逻辑进行认证校验
        // 真实的检查用户名、密码是否正确匹配
        UserObject userObj = checkLoginToSystem(userName, passWord, clientIP);
        if(userObj == null || (userObj != null && "".equals(userObj.getId()))){
            // 记录登录错误信息
            updateLogonInfo(existUserObj.getId(), false);
            // 用户名或密码错误
            res = new LogonResult(false, getThisI18n("userNameOrPwdWrong"));
            // 重新查出用户的登录记录信息
            userLogonObj = getUserLogonObj(existUserObj.getId());
            
            // 计算错误次数是否超出密码策略的限制
            if (userLogonObj != null
                    && !RightControlUtil.isAdmin(userName)
                    && !RightControlUtil.isDeveloper(userName)) {
                wrongNum = userLogonObj.getPlWrongNum();
                lastLogonTime = userLogonObj.getPlLogonTime() + 1;
                systemTime = rmcd.getSystemTime();
                timeGap = compare_time(lastLogonTime, systemTime, true);
                if(wrongNum>=1 && wrongNum< defaultWrongNum){
                    res.setMessage(res.getMessage()+"还有"+(defaultWrongNum-wrongNum)+"次机会将被锁定");
                }
                if (wrongNum >= defaultWrongNum && timeGap < defaultLogonTime) {
                    // 用户登陆失败时候记录相关日志信息
                    if (!RightControlUtil.isAdminOrDeveloperOrRoot(userName)) {
                        // 登陆错误次数过多,登入系统失败!用户已被锁定!
                        rmcd.savelogFail(getThisI18n("userLoginWrongTooMuch"));
                    }
                    int remainTime = defaultLogonTime - timeGap;
                    // 记录锁定用户的日志记录
                    rmcd.blocklog(existUserObj.getId());
                    // 用户已经被锁定,请等 {0} 分钟后再尝试登录,或者找管理员解锁!
                    res = new LogonResult(false, MessageFormat.format(getThisI18n("userIsLockedPleaseWaitSomeTimeToTry"), remainTime));
                }
            }
            return res;
        }
        
        // 用户名密码正常,但有可能是停用状态
        if(userObj != null && userObj.getStatus() == 1){
            // 您的帐户已被停用,请联系管理员!
            return new LogonResult(false, getThisI18n("userIsDisabled"));
        }
        // 正常登录
        updateLogonInfo(userObj.getId(), true);
        rmcd.savelog(getThisI18n("logon"));
        res.setSuccess(true);
        res.setMessage("");
        res.setLogonedUserObject(userObj);
        // add by xchao 2017.12.13 begin 
        // 在登录结果中加入当前登录用户所代表的VCIInvationInfo对象
        res.setInvocationInfo(rmcd.getLogonedUserInvocationInfo(userObj, getClientInfo(clientIP), forBS));
        // add by xchao 2017.12.13 end 
        // 正常登录成功后的其它消息
        res = checkOtherMessage(userName, existUserObj, userObj, pwdStgObj, res);
        return res;
    }
    
    private LogonResult checkOtherMessage(
            String userName,
            UserObject existUserObj,
            UserObject userObj,
            PasswordStrategyObject pwdStgObj,
            LogonResult res) throws VCIError, VCIException {
        
        if(RightControlUtil.isAdminOrDeveloperOrRoot(userName)){
            return res;
        }
        
        
        if (!("".equals(pwdStgObj.getId()))) {// 密码策略是否为空
            defaultWrongNum = pwdStgObj.getRetryTime(); // 获取密码策略规定的错误登录次数
            defaultLogonTime = pwdStgObj.getLockTime(); // 获取密码策略规定的锁定时间
            dafaultOverdueDay = pwdStgObj.getOverdueDay(); // 获取密码规则的过期天数
            dafaultRemideDay = pwdStgObj.getRemideDay(); // 获取密码策略规定的密码快过期提醒天数(提前xx天开始提醒该修改密码)
        }
        
        String password = userObj.getPwd();
        int requiredType = pwdStgObj.getRequiredType(); // 必填种类
        int containsTypes = pwdStgObj.getCharTypes();// 包含字符类型
        
        //判断密码属于哪种密码策略
//        CombinationObject[] combinationObjs = rmcd.fetchCombinationsByPstId(pwdStgObj.getId());
//        for (CombinationObject combObj : combinationObjs){
//            List<String> list = new ArrayList<String>();
//            CombinationValueObject[] combValObj = rmcd.fetchCombinationValuesByParentId(combObj.getId());
//            for (CombinationValueObject obj : combValObj){
//                list.add(obj.getValue());
//            }
//            for (int i = 0 ; i < userObj.getPwd().length() ;i ++){
//                String a = ""+userObj.getPwd().charAt(i);
//                if (list.contains(a)){
//                    actualType +=1 ;
//                    break;
//                }
//            }
//        }
        int actualTypes = 0;
        int typeCount = 0;
        {
            
            String symbol = "[ _`~!@#$%^&*()-+={[}]|\\'\":;,.<>/?";
            
            for (int i = 0 ; i < password.length() ;i ++){
                char c = password.charAt(i);
                if (Character.isDigit(c))
                    actualTypes |= 0x01;
                else if (Character.isLowerCase(c))
                    actualTypes |= 0x02;
                else if (Character.isUpperCase(c))
                    actualTypes |= 0x04;
                else if (symbol.indexOf(c) > -1)
                    actualTypes |= 0x08;
            }
            
            for (int i = 0; i < 4; i++) {
                int type = (int)Math.pow(2, i);
                if ((actualTypes & type) == type)
                    typeCount++;
            }
            
            if ((actualTypes & containsTypes) != actualTypes || typeCount < requiredType){
                res.setOtherMessage(getThisI18n("userPwdStagIsUpdatePleaseChange"));
                res.setNeedChangePassword(true);
            }
        }
 
        
        long pwdUpdateTime = userObj.getPwdUpdateTime();
        long systemTime = rmcd.getSystemTime();
        int date = compare_time(pwdUpdateTime, systemTime, false);
        //if ("1970-01-01 00:00:00.0".equals(pwdUpdateTime.toString())) {
        if (0 == pwdUpdateTime) {
            // 您的密码是管理员初始的密码,需要修改密码才能进行其它操作!
            res.setOtherMessage(getThisI18n("userPwdIsInitPleaseChange"));
            res.setNeedChangePassword(true);
        } else if (date > dafaultOverdueDay && userObj.getUserType() >= 1) {
            // 您的密码已经过期,请进行修改!
            res.setOtherMessage(getThisI18n("userPwdIsExpiredPleaseChange"));
            res.setNeedChangePassword(true);
        //} else if (actualType < mimacelue) {
        } else if ((actualTypes & containsTypes) != actualTypes || typeCount < requiredType){
            // 您的密码策略已经修改,需要修改密码才能进行其它操作!
            res.setOtherMessage(getThisI18n("userPwdStagIsUpdatePleaseChange"));
            res.setNeedChangePassword(true);
        } else if ((dafaultOverdueDay > date)
                && (dafaultOverdueDay - date <= dafaultRemideDay)
                && userObj.getUserType() >= 1) {
            int pwValidity = dafaultOverdueDay - date;
            // 您的密码有效期还有" + pwValidity + "天,请注意修改!
            res.setOtherMessage(MessageFormat.format(getThisI18n("userPwdHasSomeDayExpire"), pwValidity));
            res.setNeedChangePassword(false);
        }  else if (RightControlUtil.isThreeAdmin(userName) && checkLogSpaced()) {
            // 日志存储将满,请及时清理!
            res.setOtherMessage(getThisI18n("logDataIsTooMuch"));
            res.setNeedChangePassword(false);
        }
        return res;
    }
    
    private UserEntityObject getUserEntityObject(String userName, String clientIP) {
        UserEntityObject obj = new UserEntityObject();
        obj.setUserName(userName);
        obj.setIp(clientIP);
        // 登录模块
        obj.setModules(getThisI18n("logonModule"));
        return obj;
    }
    
    /**
     * 日志空间是否将满
     * 
     * @return
     * @throws VCIError
     * @throws VCIException
     */
    private boolean checkLogSpaced() throws VCIError, VCIException {
        DataSourceInfo dsInfo = ClientSession.getFrameworkService()
                .getDataSourceInfo();// 系统数据信息
        AppConfigDetailObject logMaxCount = new AppConfigDetailClientDelegate(
                null).getAppConfigDetailByKey("LogMaxCount");
        String logMaxCountValue = logMaxCount.getValue();// 系统日志最大条数
        if(logMaxCountValue.equals("")||logMaxCountValue.length()<1){
            logMaxCountValue="100000";
        }
        String logCount =dsInfo.pllogCount;// 系统日志实际条数
        float logRate = Float.parseFloat(logCount)
                / Float.parseFloat(logMaxCountValue);
        if (logRate >= 0.9) {
            return true;
        }
        return false;
    }
 
 
    /**
     * 
     * <p>
     * 根据当前登录用户名和密码查询系统是否有此用户
     * </p>
     * 
     * @time 2013-3-19
     * @return 当前用户对象
     * @throws VCIException
     *             查询过程过发生异常
     */
    private UserObject checkLoginToSystem(String userName, String passWord, String clientIP) throws VCIException {
        String desPassword = passWord;
        /*
         * if(!(RightControlUtil.isAdminOrDeveloper(userName))){
         *//**
         * 将登录界面中输入的密码加密
         */
        /*
         * ThreeDES des = new ThreeDES();// 实例化一个对像
         * des.getKey("daliantan0v0");// 生成密匙 desPassword =
         * des.getEncString(password);// 加密字符串,返回String的密文 }
         */
        return rmcd.checkLogin(userName, desPassword, getClientInfo(clientIP));
    }
    
    private ClientInfo getClientInfo(String clientIP){
        ClientInfo client = new ClientInfo();
        client.setIp(clientIP);
        return client;
    }
    /**
     * 更新用户的登录信息。成功登录,错误次数改为0,登录时间改为当前时间; 登录失败,错误次数加1,登录时间改为当前时间。
     * 
     * @param userId
     * @param flag
     * @throws VCIError
     */
    private void updateLogonInfo(String userId, boolean flag)
            throws VCIException {
        rmcd.updateLogonInfo(userId, flag);
    }
 
    /**
     * 根据登录的用户名获取将要被锁的账户
     * 
     * @return
     * @throws VCIError
     */
    private UserObject getUserObjToLock(String userName) throws VCIException {
        return rmcd.getUserObjToLock(userName);
    }
    
    /**
     * 根据用户获取账户登录信息
     * 
     * @param userId
     * @return
     * @throws VCIError
     */
    private UserLogonObject getUserLogonObj(String userId) throws VCIException {
        return rmcd.getUserLogonObj(userId);
    }
 
    /**
     * 求两个时间相隔多久
     * 
     * @param DATE1
     * @param DATE2
     * @param flag
     * @return
     */
    private int compare_time(long DATE1, long DATE2, boolean flag) {
//        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSS");
        Date dt1 = null;
        //dt1 = df.parse(DATE1);
        dt1 = new Date(DATE1);
        
        // 相差的毫秒数
        long millis = DATE2 - dt1.getTime();
        // 相差的秒数
        long secnods = millis / 1000;                        
        // 相差的天数
        long days = secnods / (24*60*60);
        // 相差的小时数
        long hours = secnods / (60*60);
        // 相差的分钟数
        long minutes = secnods / (60); 
        
        if(flag){
            return (int)minutes;
        } else {
            return (int)days;
        }
                
//        long seconds = (DATE2 - dt1.getTime()) / 1000;
//        long date = seconds / (24 * 60 * 60); // 相差的天数
//        long hour = (seconds - date * 24 * 60 * 60) / (60 * 60);// 相差的小时数
//        long minut = (seconds - date * 24 * 60 * 60 - hour * 60 * 60) / (60);// 相差的分钟数
//        // long second = (seconds-date*24*60*60-hour*60*60-minut*60);//相差的秒数
//        if (flag) {
//            return (int) (minut); // 返回分钟数
//        } else {
//            return (int) (date); // 返回天数
//        }
    }
 
    
}