diff --git a/README.md b/README.md index cc19400..b20719d 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,6 @@ # open-JSD-9519 -JSD-9519 开机域认证 \ No newline at end of file +JSD-9519 开机域认证\ +免责说明:该源码为第三方爱好者提供,不保证源码和方案的可靠性,也不提供任何形式的源码教学指导和协助!\ +仅作为开发者学习参考使用!禁止用于任何商业用途!\ +为保护开发者隐私,开发者信息已隐去!若原开发者希望公开自己的信息,可联系hugh处理。 \ No newline at end of file diff --git a/plugin.xml b/plugin.xml new file mode 100644 index 0000000..1ba29b0 --- /dev/null +++ b/plugin.xml @@ -0,0 +1,22 @@ + + com.fr.plugin.computer.domain.login + + yes + 1.0 + 10.0 + 2018-03-12 + fr.open + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/java/com/fr/plugin/domainlogin/DomainLoginPerformanceMonitor.java b/src/main/java/com/fr/plugin/domainlogin/DomainLoginPerformanceMonitor.java new file mode 100644 index 0000000..098ef80 --- /dev/null +++ b/src/main/java/com/fr/plugin/domainlogin/DomainLoginPerformanceMonitor.java @@ -0,0 +1,27 @@ +package com.fr.plugin.domainlogin; + +import com.fr.log.FineLoggerFactory; +import com.fr.plugin.context.PluginContext; +import com.fr.plugin.observer.inner.AbstractPluginLifecycleMonitor; +import com.fr.plugin.transform.FunctionRecorder; +import com.fr.record.analyzer.EnableMetrics; + +import java.nio.charset.StandardCharsets; + +@EnableMetrics +@FunctionRecorder +public class DomainLoginPerformanceMonitor extends AbstractPluginLifecycleMonitor { + + @Override + public void afterRun(PluginContext pluginContext) { + FineLoggerFactory.getLogger().info(pluginContext.getName() + "插件启动完成"); + + + + } + + @Override + public void beforeStop(PluginContext pluginContext) { + FineLoggerFactory.getLogger().info(pluginContext.getName()+"插件即将停止"); + } +} diff --git a/src/main/java/com/fr/plugin/domainlogin/beans/DomainLoginBean.java b/src/main/java/com/fr/plugin/domainlogin/beans/DomainLoginBean.java new file mode 100644 index 0000000..28feb0b --- /dev/null +++ b/src/main/java/com/fr/plugin/domainlogin/beans/DomainLoginBean.java @@ -0,0 +1,22 @@ +package com.fr.plugin.domainlogin.beans; + +public class DomainLoginBean { + private String userInfo; + private long timestamp; + + public String getUserInfo() { + return userInfo; + } + + public long getTimestamp() { + return timestamp; + } + + public void setUserInfo(String userInfo) { + this.userInfo = userInfo; + } + + public void setTimestamp(long timestamp) { + this.timestamp = timestamp; + } +} diff --git a/src/main/java/com/fr/plugin/domainlogin/controller/DomainLoginController.java b/src/main/java/com/fr/plugin/domainlogin/controller/DomainLoginController.java new file mode 100644 index 0000000..98dc4f3 --- /dev/null +++ b/src/main/java/com/fr/plugin/domainlogin/controller/DomainLoginController.java @@ -0,0 +1,91 @@ +package com.fr.plugin.domainlogin.controller; + +import com.fr.decision.authority.data.User; +import com.fr.decision.webservice.Response; +import com.fr.decision.webservice.annotation.LoginStatusChecker; +import com.fr.decision.webservice.bean.authentication.LoginRequestInfoBean; +import com.fr.decision.webservice.bean.authentication.LoginResponseInfoBean; +import com.fr.decision.webservice.utils.DecisionServiceConstants; +import com.fr.decision.webservice.v10.login.LoginService; +import com.fr.decision.webservice.v10.user.UserService; +import com.fr.plugin.domainlogin.beans.DomainLoginBean; +import com.fr.security.encryption.transmission.impl.AESTransmissionEncryption; +import com.fr.third.springframework.stereotype.Controller; +import com.fr.third.springframework.web.bind.annotation.RequestBody; +import com.fr.third.springframework.web.bind.annotation.RequestMapping; +import com.fr.third.springframework.web.bind.annotation.RequestMethod; +import com.fr.third.springframework.web.bind.annotation.ResponseBody; +import com.fr.web.controller.decision.api.auth.LoginResource; +import com.fr.web.controller.decision.api.entry.HomePageResource; +import com.fr.plugin.domainlogin.util.CBCDesUtil; +import com.fr.log.FineLoggerFactory; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.nio.charset.StandardCharsets; +import java.util.Date; + +@Controller +@LoginStatusChecker( + required = false //不需要验证是否登录 +) +public class DomainLoginController { + + private final static int MAX_LOGIN_DURATION = 2*60*1000; + + @RequestMapping( + value = {"/localDomain/login"}, + method = {RequestMethod.POST} + ) + @ResponseBody + public Response localDomainLogin(HttpServletRequest req, HttpServletResponse res, @RequestBody DomainLoginBean loginBean) throws Exception { + + String userInfo = loginBean.getUserInfo();// "Q8hphot6OxPHwCfpeofrbQ=="; + FineLoggerFactory.getLogger().info("获取到的加密信息为:"+userInfo); + String desKey = "desddddd"; + String username = ""; + try{ + String decodeValue = CBCDesUtil.decodeValue(desKey,userInfo); + username = decodeValue.split("\\\\")[1]; + FineLoggerFactory.getLogger().info("解密结果为:"+username); + } + catch(Exception ex){ + ex.printStackTrace(); + FineLoggerFactory.getLogger().info("解密失败.."); + return Response.error("11300007","登录失败"); + } + + //先判断时间戳能对上不 + long timeStamp = loginBean.getTimestamp()+MAX_LOGIN_DURATION; + long currentTimeStamp = new Date().getTime(); + if(timeStamp < currentTimeStamp){ + FineLoggerFactory.getLogger().info("当前时间戳超时了。。。"); + return Response.error("11300007","登录失败"); + } + else{ + //判断该用户存在不 + User user = UserService.getInstance().getUserByUserName(username); + if(user == null){ + FineLoggerFactory.getLogger().info("决策系统里不存在用户:"+username); + return Response.error("21300006","用户不可用"); + } + + // LoginRequestInfoBean infoBean = new LoginRequestInfoBean(); + // infoBean.setEncrypted(true); + // infoBean.setPassword(AESTransmissionEncryption.getInstance().encrypt(loginBean.getPasswd())); + // infoBean.setUsername(loginBean.getUserName()); + // infoBean.setValidity(-1); + // LoginResponseInfoBean responseBean = LoginService.getInstance().login(req,res,infoBean); + String token = LoginService.getInstance().login(req,res,username); + FineLoggerFactory.getLogger().info("登录返回token:"+token); + if(token != null){ + req.setAttribute(DecisionServiceConstants.FINE_AUTH_TOKEN_NAME, token); + return Response.ok(token); + } + else{ + return Response.error("11300007","登录失败"); + } + } + + } + +} diff --git a/src/main/java/com/fr/plugin/domainlogin/controller/DomainLoginControllerProvider.java b/src/main/java/com/fr/plugin/domainlogin/controller/DomainLoginControllerProvider.java new file mode 100644 index 0000000..dbaa7b5 --- /dev/null +++ b/src/main/java/com/fr/plugin/domainlogin/controller/DomainLoginControllerProvider.java @@ -0,0 +1,12 @@ +package com.fr.plugin.domainlogin.controller; + +import com.fr.decision.fun.impl.AbstractControllerRegisterProvider; + +public class DomainLoginControllerProvider extends AbstractControllerRegisterProvider { + @Override + public Class[] getControllers() { + return new Class[]{ + DomainLoginController.class + }; + } +} diff --git a/src/main/java/com/fr/plugin/domainlogin/loginout/DomaintLogInOutEventProvider.java b/src/main/java/com/fr/plugin/domainlogin/loginout/DomaintLogInOutEventProvider.java new file mode 100644 index 0000000..c6c8e18 --- /dev/null +++ b/src/main/java/com/fr/plugin/domainlogin/loginout/DomaintLogInOutEventProvider.java @@ -0,0 +1,19 @@ +package com.fr.plugin.domainlogin.loginout; + +import com.fr.decision.fun.impl.AbstractLogInOutEventProvider; +import com.fr.decision.webservice.login.LogInOutResultInfo; +import com.fr.log.FineLoggerFactory; +import javax.servlet.http.Cookie; +public class DomaintLogInOutEventProvider extends AbstractLogInOutEventProvider{ + + + + @Override + public String logoutAction( LogInOutResultInfo result ) { + FineLoggerFactory.getLogger().info(result.getUsername()+"log out!"); + Cookie cookie = new Cookie("domainloginflag","1"); + cookie.setPath("/"); + result.getResponse().addCookie(cookie); + return null; + } +} diff --git a/src/main/java/com/fr/plugin/domainlogin/util/Base64.java b/src/main/java/com/fr/plugin/domainlogin/util/Base64.java new file mode 100644 index 0000000..0849d8b --- /dev/null +++ b/src/main/java/com/fr/plugin/domainlogin/util/Base64.java @@ -0,0 +1,308 @@ +/* + * Copyright (c) 2007, 2021, Oracle and/or its affiliates. All rights reserved. + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + */ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 + * + * http://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 com.fr.plugin.domainlogin.util; + +/** + * This class provides encode/decode for RFC 2045 Base64 as + * defined by RFC 2045, N. Freed and N. Borenstein. + * RFC 2045: Multipurpose Internet Mail Extensions (MIME) + * Part One: Format of Internet Message Bodies. Reference + * 1996 Available at: http://www.ietf.org/rfc/rfc2045.txt + * This class is used by XML Schema binary format validation + * + * This implementation does not encode/decode streaming + * data. You need the data that you will encode/decode + * already on a byte arrray. + * + * @xerces.internal + * + * @author Jeffrey Rodriguez + * @author Sandy Gao + */ +public final class Base64 { + + static private final int BASELENGTH = 128; + static private final int LOOKUPLENGTH = 64; + static private final int TWENTYFOURBITGROUP = 24; + static private final int EIGHTBIT = 8; + static private final int SIXTEENBIT = 16; + static private final int SIXBIT = 6; + static private final int FOURBYTE = 4; + static private final int SIGN = -128; + static private final char PAD = '='; + static private final boolean fDebug = false; + static final private byte [] base64Alphabet = new byte[BASELENGTH]; + static final private char [] lookUpBase64Alphabet = new char[LOOKUPLENGTH]; + + static { + + for (int i = 0; i < BASELENGTH; ++i) { + base64Alphabet[i] = -1; + } + for (int i = 'Z'; i >= 'A'; i--) { + base64Alphabet[i] = (byte) (i-'A'); + } + for (int i = 'z'; i>= 'a'; i--) { + base64Alphabet[i] = (byte) ( i-'a' + 26); + } + + for (int i = '9'; i >= '0'; i--) { + base64Alphabet[i] = (byte) (i-'0' + 52); + } + + base64Alphabet['+'] = 62; + base64Alphabet['/'] = 63; + + for (int i = 0; i<=25; i++) + lookUpBase64Alphabet[i] = (char)('A'+i); + + for (int i = 26, j = 0; i<=51; i++, j++) + lookUpBase64Alphabet[i] = (char)('a'+ j); + + for (int i = 52, j = 0; i<=61; i++, j++) + lookUpBase64Alphabet[i] = (char)('0' + j); + lookUpBase64Alphabet[62] = (char)'+'; + lookUpBase64Alphabet[63] = (char)'/'; + + } + + protected static boolean isWhiteSpace(char octect) { + return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9); + } + + protected static boolean isPad(char octect) { + return (octect == PAD); + } + + protected static boolean isData(char octect) { + return (octect < BASELENGTH && base64Alphabet[octect] != -1); + } + + protected static boolean isBase64(char octect) { + return (isWhiteSpace(octect) || isPad(octect) || isData(octect)); + } + + /** + * Encodes hex octects into Base64 + * + * @param binaryData Array containing binaryData + * @return Encoded Base64 array + */ + public static String encode(byte[] binaryData) { + + if (binaryData == null) + return null; + + int lengthDataBits = binaryData.length*EIGHTBIT; + if (lengthDataBits == 0) { + return ""; + } + + int fewerThan24bits = lengthDataBits%TWENTYFOURBITGROUP; + int numberTriplets = lengthDataBits/TWENTYFOURBITGROUP; + int numberQuartet = fewerThan24bits != 0 ? numberTriplets+1 : numberTriplets; + char encodedData[] = null; + + encodedData = new char[numberQuartet*4]; + + byte k=0, l=0, b1=0,b2=0,b3=0; + + int encodedIndex = 0; + int dataIndex = 0; + if (fDebug) { + System.out.println("number of triplets = " + numberTriplets ); + } + + for (int i=0; i>4 ) ; + decodedData[encodedIndex++] = (byte)(((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) ); + decodedData[encodedIndex++] = (byte)( b3<<6 | b4 ); + } + + if (!isData( (d1 = base64Data[dataIndex++]) ) || + !isData( (d2 = base64Data[dataIndex++]) )) { + return null;//if found "no data" just return null + } + + b1 = base64Alphabet[d1]; + b2 = base64Alphabet[d2]; + + d3 = base64Data[dataIndex++]; + d4 = base64Data[dataIndex++]; + if (!isData( (d3 ) ) || + !isData( (d4 ) )) {//Check if they are PAD characters + if (isPad( d3 ) && isPad( d4)) { //Two PAD e.g. 3c[Pad][Pad] + if ((b2 & 0xf) != 0)//last 4 bits should be zero + return null; + byte[] tmp = new byte[ i*3 + 1 ]; + System.arraycopy( decodedData, 0, tmp, 0, i*3 ); + tmp[encodedIndex] = (byte)( b1 <<2 | b2>>4 ) ; + return tmp; + } else if (!isPad( d3) && isPad(d4)) { //One PAD e.g. 3cQ[Pad] + b3 = base64Alphabet[ d3 ]; + if ((b3 & 0x3 ) != 0)//last 2 bits should be zero + return null; + byte[] tmp = new byte[ i*3 + 2 ]; + System.arraycopy( decodedData, 0, tmp, 0, i*3 ); + tmp[encodedIndex++] = (byte)( b1 <<2 | b2>>4 ); + tmp[encodedIndex] = (byte)(((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) ); + return tmp; + } else { + return null;//an error like "3c[Pad]r", "3cdX", "3cXd", "3cXX" where X is non data + } + } else { //No PAD e.g 3cQl + b3 = base64Alphabet[ d3 ]; + b4 = base64Alphabet[ d4 ]; + decodedData[encodedIndex++] = (byte)( b1 <<2 | b2>>4 ) ; + decodedData[encodedIndex++] = (byte)(((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) ); + decodedData[encodedIndex++] = (byte)( b3<<6 | b4 ); + + } + + return decodedData; + } + + /** + * remove WhiteSpace from MIME containing encoded Base64 data. + * + * @param data the byte array of base64 data (with WS) + * @return the new length + */ + protected static int removeWhiteSpace(char[] data) { + if (data == null) + return 0; + + // count characters that's not whitespace + int newSize = 0; + int len = data.length; + for (int i = 0; i < len; i++) { + if (!isWhiteSpace(data[i])) + data[newSize++] = data[i]; + } + return newSize; + } +} diff --git a/src/main/java/com/fr/plugin/domainlogin/util/CBCDesUtil.java b/src/main/java/com/fr/plugin/domainlogin/util/CBCDesUtil.java new file mode 100644 index 0000000..972cf13 --- /dev/null +++ b/src/main/java/com/fr/plugin/domainlogin/util/CBCDesUtil.java @@ -0,0 +1,408 @@ +package com.fr.plugin.domainlogin.util; + +import java.security.Key; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; +import javax.crypto.Cipher; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.DESKeySpec; +import javax.crypto.spec.IvParameterSpec; +public class CBCDesUtil { + public static final String ALGORITHM_DES = "DES/CBC/PKCS5Padding"; + + /** + * DES算法,加密 + * + * @param data 待加密字符串 + * @param key 加密私钥,长度不能够小于8位 + * @return 加密后的字节数组,一般结合Base64编码使用 + * @throws Exception 异常 + */ + public static String encode(String key, String data) throws Exception { + return encode(key, data.getBytes()); + } + + /** + * DES算法,加密 + * + * @param data 待加密字符串 + * @param key 加密私钥,长度不能够小于8位 + * @return 加密后的字节数组,一般结合Base64编码使用 + * @throws Exception 异常 + */ + public static String encode(String key, byte[] data) throws Exception { + try { + DESKeySpec dks = new DESKeySpec(key.getBytes()); + + SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); + //key的长度不能够小于8位字节 + Key secretKey = keyFactory.generateSecret(dks); + Cipher cipher = Cipher.getInstance(ALGORITHM_DES); + IvParameterSpec iv = new IvParameterSpec(key.getBytes()); + AlgorithmParameterSpec paramSpec = iv; + cipher.init(Cipher.ENCRYPT_MODE, secretKey, paramSpec); + + byte[] bytes = cipher.doFinal(data); + return Base64.encode(bytes); + } catch (Exception e) { + throw new Exception(e); + } + } + + /** + * DES算法,解密 + * + * @param data 待解密字符串 + * @param key 解密私钥,长度不能够小于8位 + * @return 解密后的字节数组 + * @throws Exception 异常 + */ + public static byte[] decode(String key, byte[] data) throws Exception { + try { + SecureRandom sr = new SecureRandom(); + DESKeySpec dks = new DESKeySpec(key.getBytes()); + SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); + //key的长度不能够小于8位字节 + Key secretKey = keyFactory.generateSecret(dks); + Cipher cipher = Cipher.getInstance(ALGORITHM_DES); + IvParameterSpec iv = new IvParameterSpec(key.getBytes()); + AlgorithmParameterSpec paramSpec = iv; + cipher.init(Cipher.DECRYPT_MODE, secretKey, paramSpec); + return cipher.doFinal(data); + } catch (Exception e) { + throw new Exception(e); + } + } + + /** + * 获取编码后的值 + * + * @param key + * @param data + * @return + * @throws Exception + * @throws Exception + */ + public static String decodeValue(String key, String data) throws Exception { + byte[] datas; + String value = null; + + datas = decode(key, Base64.decode(data)); + + value = new String(datas); + if (value.equals("")) { + throw new Exception(); + } + return value; + } + + + /* + * Copyright (c) 2007, 2021, Oracle and/or its affiliates. All rights reserved. + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + */ + /* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 + * + * http://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. + */ + + + /** + * This class provides encode/decode for RFC 2045 Base64 as + * defined by RFC 2045, N. Freed and N. Borenstein. + * RFC 2045: Multipurpose Internet Mail Extensions (MIME) + * Part One: Format of Internet Message Bodies. Reference + * 1996 Available at: http://www.ietf.org/rfc/rfc2045.txt + * This class is used by XML Schema binary format validation + * + * This implementation does not encode/decode streaming + * data. You need the data that you will encode/decode + * already on a byte arrray. + * + * @xerces.internal + * + * @author Jeffrey Rodriguez + * @author Sandy Gao + */ + public static final class Base64 { + + static private final int BASELENGTH = 128; + static private final int LOOKUPLENGTH = 64; + static private final int TWENTYFOURBITGROUP = 24; + static private final int EIGHTBIT = 8; + static private final int SIXTEENBIT = 16; + static private final int SIXBIT = 6; + static private final int FOURBYTE = 4; + static private final int SIGN = -128; + static private final char PAD = '='; + static private final boolean fDebug = false; + static final private byte [] base64Alphabet = new byte[BASELENGTH]; + static final private char [] lookUpBase64Alphabet = new char[LOOKUPLENGTH]; + + static { + + for (int i = 0; i < BASELENGTH; ++i) { + base64Alphabet[i] = -1; + } + for (int i = 'Z'; i >= 'A'; i--) { + base64Alphabet[i] = (byte) (i-'A'); + } + for (int i = 'z'; i>= 'a'; i--) { + base64Alphabet[i] = (byte) ( i-'a' + 26); + } + + for (int i = '9'; i >= '0'; i--) { + base64Alphabet[i] = (byte) (i-'0' + 52); + } + + base64Alphabet['+'] = 62; + base64Alphabet['/'] = 63; + + for (int i = 0; i<=25; i++) + lookUpBase64Alphabet[i] = (char)('A'+i); + + for (int i = 26, j = 0; i<=51; i++, j++) + lookUpBase64Alphabet[i] = (char)('a'+ j); + + for (int i = 52, j = 0; i<=61; i++, j++) + lookUpBase64Alphabet[i] = (char)('0' + j); + lookUpBase64Alphabet[62] = (char)'+'; + lookUpBase64Alphabet[63] = (char)'/'; + + } + + protected static boolean isWhiteSpace(char octect) { + return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9); + } + + protected static boolean isPad(char octect) { + return (octect == PAD); + } + + protected static boolean isData(char octect) { + return (octect < BASELENGTH && base64Alphabet[octect] != -1); + } + + protected static boolean isBase64(char octect) { + return (isWhiteSpace(octect) || isPad(octect) || isData(octect)); + } + + /** + * Encodes hex octects into Base64 + * + * @param binaryData Array containing binaryData + * @return Encoded Base64 array + */ + public static String encode(byte[] binaryData) { + + if (binaryData == null) + return null; + + int lengthDataBits = binaryData.length*EIGHTBIT; + if (lengthDataBits == 0) { + return ""; + } + + int fewerThan24bits = lengthDataBits%TWENTYFOURBITGROUP; + int numberTriplets = lengthDataBits/TWENTYFOURBITGROUP; + int numberQuartet = fewerThan24bits != 0 ? numberTriplets+1 : numberTriplets; + char encodedData[] = null; + + encodedData = new char[numberQuartet*4]; + + byte k=0, l=0, b1=0,b2=0,b3=0; + + int encodedIndex = 0; + int dataIndex = 0; + if (fDebug) { + System.out.println("number of triplets = " + numberTriplets ); + } + + for (int i=0; i>4 ) ; + decodedData[encodedIndex++] = (byte)(((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) ); + decodedData[encodedIndex++] = (byte)( b3<<6 | b4 ); + } + + if (!isData( (d1 = base64Data[dataIndex++]) ) || + !isData( (d2 = base64Data[dataIndex++]) )) { + return null;//if found "no data" just return null + } + + b1 = base64Alphabet[d1]; + b2 = base64Alphabet[d2]; + + d3 = base64Data[dataIndex++]; + d4 = base64Data[dataIndex++]; + if (!isData( (d3 ) ) || + !isData( (d4 ) )) {//Check if they are PAD characters + if (isPad( d3 ) && isPad( d4)) { //Two PAD e.g. 3c[Pad][Pad] + if ((b2 & 0xf) != 0)//last 4 bits should be zero + return null; + byte[] tmp = new byte[ i*3 + 1 ]; + System.arraycopy( decodedData, 0, tmp, 0, i*3 ); + tmp[encodedIndex] = (byte)( b1 <<2 | b2>>4 ) ; + return tmp; + } else if (!isPad( d3) && isPad(d4)) { //One PAD e.g. 3cQ[Pad] + b3 = base64Alphabet[ d3 ]; + if ((b3 & 0x3 ) != 0)//last 2 bits should be zero + return null; + byte[] tmp = new byte[ i*3 + 2 ]; + System.arraycopy( decodedData, 0, tmp, 0, i*3 ); + tmp[encodedIndex++] = (byte)( b1 <<2 | b2>>4 ); + tmp[encodedIndex] = (byte)(((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) ); + return tmp; + } else { + return null;//an error like "3c[Pad]r", "3cdX", "3cXd", "3cXX" where X is non data + } + } else { //No PAD e.g 3cQl + b3 = base64Alphabet[ d3 ]; + b4 = base64Alphabet[ d4 ]; + decodedData[encodedIndex++] = (byte)( b1 <<2 | b2>>4 ) ; + decodedData[encodedIndex++] = (byte)(((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) ); + decodedData[encodedIndex++] = (byte)( b3<<6 | b4 ); + + } + + return decodedData; + } + + /** + * remove WhiteSpace from MIME containing encoded Base64 data. + * + * @param data the byte array of base64 data (with WS) + * @return the new length + */ + protected static int removeWhiteSpace(char[] data) { + if (data == null) + return 0; + + // count characters that's not whitespace + int newSize = 0; + int len = data.length; + for (int i = 0; i < len; i++) { + if (!isWhiteSpace(data[i])) + data[newSize++] = data[i]; + } + return newSize; + } + } + +} diff --git a/src/main/java/com/fr/plugin/domainlogin/util/Des.java b/src/main/java/com/fr/plugin/domainlogin/util/Des.java new file mode 100644 index 0000000..d6bc420 --- /dev/null +++ b/src/main/java/com/fr/plugin/domainlogin/util/Des.java @@ -0,0 +1,99 @@ +package com.fr.plugin.domainlogin.util; + +import java.security.Key; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; +import javax.crypto.Cipher; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.DESKeySpec; +import javax.crypto.spec.IvParameterSpec; + +public class Des { + public static final String ALGORITHM_DES = "DES/CBC/PKCS5Padding"; + + /** + * DES算法,加密 + * + * @param data 待加密字符串 + * @param key 加密私钥,长度不能够小于8位 + * @return 加密后的字节数组,一般结合Base64编码使用 + * @throws Exception 异常 + */ + public static String encode(String key, String data) throws Exception { + return encode(key, data.getBytes()); + } + + /** + * DES算法,加密 + * + * @param data 待加密字符串 + * @param key 加密私钥,长度不能够小于8位 + * @return 加密后的字节数组,一般结合Base64编码使用 + * @throws Exception 异常 + */ + public static String encode(String key, byte[] data) throws Exception { + try { + DESKeySpec dks = new DESKeySpec(key.getBytes()); + + SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); + //key的长度不能够小于8位字节 + Key secretKey = keyFactory.generateSecret(dks); + Cipher cipher = Cipher.getInstance(ALGORITHM_DES); + IvParameterSpec iv = new IvParameterSpec(key.getBytes()); + AlgorithmParameterSpec paramSpec = iv; + cipher.init(Cipher.ENCRYPT_MODE, secretKey, paramSpec); + + byte[] bytes = cipher.doFinal(data); + return Base64.encode(bytes); + } catch (Exception e) { + throw new Exception(e); + } + } + + /** + * DES算法,解密 + * + * @param data 待解密字符串 + * @param key 解密私钥,长度不能够小于8位 + * @return 解密后的字节数组 + * @throws Exception 异常 + */ + public static byte[] decode(String key, byte[] data) throws Exception { + try { + SecureRandom sr = new SecureRandom(); + DESKeySpec dks = new DESKeySpec(key.getBytes()); + SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); + //key的长度不能够小于8位字节 + Key secretKey = keyFactory.generateSecret(dks); + Cipher cipher = Cipher.getInstance(ALGORITHM_DES); + IvParameterSpec iv = new IvParameterSpec(key.getBytes()); + AlgorithmParameterSpec paramSpec = iv; + cipher.init(Cipher.DECRYPT_MODE, secretKey, paramSpec); + return cipher.doFinal(data); + } catch (Exception e) { + throw new Exception(e); + } + } + + /** + * 获取编码后的值 + * + * @param key + * @param data + * @return + * @throws Exception + * @throws Exception + */ + public static String decodeValue(String key, String data) throws Exception { + byte[] datas; + String value = null; + + datas = decode(key, Base64.decode(data)); + + value = new String(datas); + if (value.equals("")) { + throw new Exception(); + } + return value; + } +} diff --git a/src/main/java/com/fr/plugin/domainlogin/webresource/DomainLoginComponent.java b/src/main/java/com/fr/plugin/domainlogin/webresource/DomainLoginComponent.java new file mode 100644 index 0000000..962499e --- /dev/null +++ b/src/main/java/com/fr/plugin/domainlogin/webresource/DomainLoginComponent.java @@ -0,0 +1,17 @@ +package com.fr.plugin.domainlogin.webresource; + +import com.fr.web.struct.Component; +import com.fr.web.struct.browser.RequestClient; +import com.fr.web.struct.category.ScriptPath; + +public class DomainLoginComponent extends Component { + + public static DomainLoginComponent KEY = new DomainLoginComponent(); + + + @Override + public ScriptPath script(RequestClient req) { + return ScriptPath.build("/com/fr/plugin/domainlogin/jscss/domain_login.js"); + } + +} diff --git a/src/main/java/com/fr/plugin/domainlogin/webresource/DomainLoginWebResourceProvider.java b/src/main/java/com/fr/plugin/domainlogin/webresource/DomainLoginWebResourceProvider.java new file mode 100644 index 0000000..8d59a8e --- /dev/null +++ b/src/main/java/com/fr/plugin/domainlogin/webresource/DomainLoginWebResourceProvider.java @@ -0,0 +1,20 @@ +package com.fr.plugin.domainlogin.webresource; + +import com.fr.decision.fun.impl.AbstractWebResourceProvider; +import com.fr.decision.web.LoginComponent; +import com.fr.decision.web.MainComponent; +import com.fr.web.struct.Atom; + +public class DomainLoginWebResourceProvider extends AbstractWebResourceProvider { + + @Override + public Atom attach() { + return LoginComponent.KEY; + } + + public Atom client() { + + return DomainLoginComponent.KEY; + } + +} diff --git a/src/main/resources/com/fr/plugin/domainlogin/jscss/domain_login.js b/src/main/resources/com/fr/plugin/domainlogin/jscss/domain_login.js new file mode 100644 index 0000000..fc01c0c --- /dev/null +++ b/src/main/resources/com/fr/plugin/domainlogin/jscss/domain_login.js @@ -0,0 +1,325 @@ +; (function () { + // $("
").addClass("plugin-jscssinput-demo").html("Hello World!").appendTo("body"); + console.log("本地域登录js启动...") + + + //定义获取本地域的用户名信息 + function getLocalDomainUserInfo(callback) { + $.ajax({ + type: "POST", + //url: "${base_url}common/login.do", + url: "http://10.5.0.138:5006/api/Login", + dataType: "jsonp", + // data: {username:username, userpass:userpass, t:Math.random()}, + success: function (data) { + var userInfo = data; + console.log("userInfo:" + userInfo) + callback(userInfo) + //这里的data是DES加密的 + }, + error: function () { + $(".alert-error").text('登录失败'); + alert('系统繁忙'); + } + }); + + } + + + function domainLogin() { + console.log("域登录....") + //本地域用户 + getLocalDomainUserInfo((userInfo) => { + //时间戳 + var timestamp = new Date().getTime(); + + Dec.reqPost("/localDomain/login", { + "userInfo": userInfo, + "timestamp": timestamp, + }, function (res) { + if (res["errorMsg"] != undefined) { + console.log("/localDomain/login调用失败结果:" + res["errorMsg"]); + BI.Msg.alert("提示", res["errorMsg"], function (v) { + + }); + } + else { + console.log("/localDomain/login调用结果:" + res.data); + BI.Cache.addCookie(DecCst.Cookie.TOKEN, res.data, Dec.loginConfig.cookiePath, 0); + window.location.href = "/webroot/decision"; + } + + }) + }); + + } + + + setTimeout(() => { + var domainloginflag = BI.Cache.getCookie("domainloginflag"); + console.log("domainloginflag:" + domainloginflag); + if (domainloginflag != "1") { + + Dec.Msg.confirm({ + "title": "系统提示", "message": "是否尝试域认证一键登录?", "callback": function (isoK) { + if (isoK) { + domainLogin(); + } + } + }); + } + }, 1000); + + + function loginCompDefine() { + console.log("进到我的登录组件了.....") + var e = BI.inherit(BI.Widget, { + props: { + baseCls: "dec-login-login" + }, + _store: function () { + return BI.Models.getModel("dec.model.login.login") + }, + watch: { + supportForgetPwd: function (e) { + this.forgetPasswordRow.setVisible(e) + }, + needSlider: function (e) { + this.sliderMasker.setVisible(e) + } + }, + render: function () { + var t = this; + this.options; + return { + type: "bi.absolute", + items: [ + { + el: { + type: "bi.vertical", + items: [ + { + type: "dec.login.login.item", + $testId: "dec-login-username", + iconCls: "login-username-font", + tgap: 50, + watermark: BI.i18nText("Dec-User_Name"), + ref: function (e) { + t.usernameRow = e + } + }, + { + type: "dec.login.login.item", + $testId: "dec-login-password", + iconCls: "login-password-font", + watermark: BI.i18nText("Dec-Password"), + inputType: "password", + ref: function (e) { + t.passwordRow = e + } + }, + + { + type: "bi.default", + bgap: 30, + cls: "clearfix", + items: [ + { + el: { + type: "bi.multi_select_item", + css: { + "float": "left" + }, + $testId: "dec-login-remember", + textLgap: 5, + iconWrapperWidth: 16, + height: 16, + text: BI.i18nText("Dec-Login_Remember"), + logic: { + dynamic: !0 + }, + ref: function (e) { + t.rememberRow = e + } + } + }, + + ] + }, + + { + type: "bi.horizontal_auto", + bgap:20, + items: [ + { + type: "bi.button", + cls: "login-button", + text: BI.i18nText("Dec-Basic_Login"), + width: 190, + height: 40, + handler: function () { + t._start() + } + } + ] + }, + { + type: "bi.horizontal_auto", + + items: [ + { + type: "bi.button", + cls: "login-button", + text: '域认证一键登录', + width: 190, + height: 40, + handler: function () { + //t._start() + domainLogin(); + } + } + ] + }, + { + el: { + type: "bi.vertical", + $testId: "dec-login-logged-chang-text", + cls: "login-error", + invisible: !0, + scrolly: !1, + items: [ + { + type: "bi.text", + tagName: "span", + whiteSpace: "normal", + text: BI.i18nText("Dec-Login_Other_Logged_Tip") + }, + { + type: "bi.text", + $testId: "dec-login-logged-chang-password", + tagName: "span", + cls: "password-btn", + text: BI.i18nText("Dec-Login_Change_Password"), + handler: function () { + t.model.isNeedVerify ? t.store.setSelectedTab(DecCst.Login.Tabs.VERIFY_BING) : t.store.setSelectedTab(DecCst.Login.Tabs.PASSWORD_OLD) + } + } + ], + ref: function (e) { + t.loginErrorRow = e + } + }, + tgap: 20 + }, + { + el: { + type: "bi.text", + $testId: "dec-login-logged-text", + cls: "login-error", + invisible: !0, + whiteSpace: "normal", + text: BI.i18nText("Dec-Login_Normal_Other_Logged_Tip"), + ref: function (e) { + t.loginNormalErrorRow = e + } + }, + tgap: 20 + }] + }, + top: 0, + right: 40, + bottom: 0, + left: 40 + }, + { + el: { + type: "bi.center_adapt", + cls: "slider-masker", + invisible: !0, + items: [{ + type: "dec.login.slider", + listeners: [{ + eventName: "EVENT_SUCCESS", + action: function () { + t._start() + } + }, { + eventName: "EVENT_CLOSE", + action: function () { + t.store.resetSlider() + } + }], + ref: function (e) { + t.sliderBar = e + } + }], + ref: function (e) { + t.sliderMasker = e + } + }, + top: 0, + right: 40, + bottom: 0, + left: 40 + } + ] + } + }, + mounted: function () { + var t = this; + this.store.initData(), + this.element.keyup(function (e) { + 13 === e.keyCode && t._start() + }) + }, + _createItems: function () { + return BI.map(BI.Constants.getConstant("dec.constant.login.way.extend"), function (e, t) { + return { + type: t.cardType + } + }) + }, + _start: function () { + var t = this + , e = this.usernameRow.getValue() + , i = this.passwordRow.getValue() + , n = this.rememberRow.isSelected() ? -2 : -1; + t.loginErrorRow.invisible(), + t.loginNormalErrorRow.invisible(), + "" !== e ? "" !== i ? (this.store.setLoginInfo({ + username: e, + validity: n, + phone: "", + captcha: "" + }), + this.store.login({ + username: e, + password: this.passwordRow.getCipher(), + validity: n, + sliderToken: this.model.sliderToken, + origin: Dec.Utils.getUrlQuery("origin"), + encrypted: !0 + }, function (e) { + t.store.resetSlider(), + e.data && e.data.accessToken ? t.fireEvent("EVENT_LOGIN", e.data) : BI.bind(BI.Services.getService("dec.service.login.login").getHandler(e.errorCode), t)(e) + })) : this.passwordRow.showError(BI.i18nText("Dec-Error_Password_Not_Null")) : this.usernameRow.showError(BI.i18nText("Dec-Error_Username_Not_Null")) + } + }); + BI.shortcut("dec.login.login1", e) + } + + loginCompDefine(); + + + BI.config("dec.login.login", function (options) { + options.type = "dec.login.login1"; // 将组件的type替换为自定义的组件 + return options; + }); + + + + + + + +})(); \ No newline at end of file diff --git a/文档/说明文档.docx b/文档/说明文档.docx new file mode 100644 index 0000000..66f5005 Binary files /dev/null and b/文档/说明文档.docx differ