Просмотр исходного кода

<feat>:新增
1、新增单点登录插件

wanghaiwu 4 дней назад
Родитель
Сommit
dd234037a3

+ 115 - 0
code/jyyy/nckd-jimin-jyyy-bd/src/main/java/nckd/jimin/jyyy/bd/common/oauth/SSOAuthtication.java

@@ -0,0 +1,115 @@
+package nckd.jimin.jyyy.bd.common.oauth;
+
+import kd.bos.dc.api.model.Account;
+import kd.bos.logging.Log;
+import kd.bos.logging.LogFactory;
+import kd.bos.login.thirdauth.app.AppAuthResult;
+import kd.bos.login.thirdauth.app.ThirdAppAuthtication;
+import kd.bos.login.thirdauth.app.UserType;
+import nckd.base.helper.CommonHelperUtils;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.lang3.StringUtils;
+import javax.servlet.http.HttpServletRequest;
+import java.util.Map;
+
+/**
+ * @author wanghaiwu_kd
+ * @date 2025/05/06
+ * @description 单点登录拦截,加固单点校验方式
+ */
+public class SSOAuthtication extends ThirdAppAuthtication {
+    private static Log logger = LogFactory.getLog(SSOAuthtication.class);
+    /**
+     * 判断该接口请求是否需要通过此插件认证
+     */
+    @Override
+    public boolean isNeedHandle(HttpServletRequest request, Account account) {
+        //加密的数据信息
+        String code = request.getParameter("kd_code");
+        if(StringUtils.isNotBlank(code)){
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     *用户身份解析
+     */
+    @Override
+    public AppAuthResult appAuthtication(HttpServletRequest request, Account account) {
+        AppAuthResult result = new AppAuthResult();
+        result.setSucceed(false);
+        try{
+            //加密的数据信息
+            String code = request.getParameter("kd_code");
+            if(StringUtils.isBlank(code)){
+                logger.info("SSOAuthtication:kd_code is null");
+
+                result.setErrorMessage("sso:kd_code is null");
+                return result;
+            }
+
+            Map<String, String> mapentity = CommonHelperUtils.getCommonParams("SSO");
+            if(mapentity == null ){
+                logger.info("SSOAuthtication:nckd_entryentity is null");
+
+                result.setErrorMessage("SSOAuthtication:未配置单点相关参数");
+                return result;
+            }
+
+            //私钥
+            String privateKey = mapentity.get("privatekey");
+            if(StringUtils.isEmpty(privateKey)){
+                logger.info("SSOAuthtication:privateKey is null");
+
+                result.setErrorMessage("SSOAuthtication:未配置单点相关参数privatekey");
+                return result;
+            }
+
+            //和第三方约定加签
+            String secret = mapentity.get("secret");
+            if(StringUtils.isEmpty(secret)){
+                logger.info("SSOAuthtication:secret is null");
+
+                result.setErrorMessage("SSOAuthtication:未配置单点相关参数secret");
+                return result;
+            }
+
+            //可以先使用SHAUtils.getSHA256Hex实现签名验证再数据解密
+            String timeStamp = request.getParameter("timeStamp");
+            String signture = request.getParameter("signture");
+            if(!SHAUtils.checkDateTime(timeStamp)) {
+                logger.info("SSOAuthtication:timeStamp check fail");
+
+                result.setErrorMessage("sso:timeStamp check fail");
+                return result;
+            }
+
+            String sign = SHAUtils.getSHA256Hex(code + timeStamp + secret);
+
+            //签名认证
+            if(StringUtils.isBlank(signture) || !signture.equals(sign)) {
+                logger.info("SSOAuthtication:sign check fail");
+
+                result.setErrorMessage("sso:sign check fail");
+                return result;
+            }
+
+            String user = new String(SSORSAUtils.decryptByKey(SSORSAUtils.getPrivateKey(Base64.decodeBase64(privateKey))
+                                        , Base64.decodeBase64(code.getBytes("UTF-8"))));
+            if(StringUtils.isBlank(user)){
+                logger.info("SSOAuthtication:user is null");
+
+                result.setErrorMessage("sso:user is null");
+                return result;
+            }
+
+            result.setUserFlag(user);
+            result.setUserType(UserType.USER_NAME);
+            result.setSucceed(true);
+        }catch (Exception e){
+            e.printStackTrace();
+        }
+        return result;
+    }
+}

+ 143 - 0
code/jyyy/nckd-jimin-jyyy-bd/src/main/java/nckd/jimin/jyyy/bd/common/oauth/SSORSAUtils.java

@@ -0,0 +1,143 @@
+package nckd.jimin.jyyy.bd.common.oauth;
+
+import org.apache.commons.codec.binary.Base64;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import java.io.ByteArrayOutputStream;
+import java.security.*;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+public class SSORSAUtils {
+
+    private static Provider provider;
+
+    static {
+        provider = new org.bouncycastle.jce.provider.BouncyCastleProvider();
+        Security.addProvider(provider);
+    }
+
+    /**
+     * 产生key pair,提供provider和random
+     * @return
+     * @throws NoSuchAlgorithmException
+     */
+    public static KeyPair generateKeyPair() throws NoSuchAlgorithmException {
+        // 产生用于安全加密的随机数
+        SecureRandom random = new SecureRandom();
+
+        KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", provider);
+        Integer length = 2048;//加密算法位数
+        generator.initialize(length, random);
+        return generator.generateKeyPair();
+    }
+
+    /**
+     * 返回一个keyBytes生成的PublicKey对象
+     * @param keyBytes
+     * @return
+     * @throws NoSuchAlgorithmException
+     * @throws InvalidKeySpecException
+     */
+    public static PublicKey getPublicKey(byte[] keyBytes) throws NoSuchAlgorithmException, InvalidKeySpecException {
+        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
+        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
+        PublicKey publicKey = keyFactory.generatePublic(keySpec);
+        return publicKey;
+    }
+
+    public static byte[] encryptByKey(Key keys, byte[] byteArray) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
+        // Cipher: 提供加密和解密功能的实例
+        // transformation: "algorithm/mode/padding"
+        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", provider);
+        // PrivateKey privateKey = keyPair.getPrivate();
+        // 初始化
+        cipher.init(Cipher.ENCRYPT_MODE, keys);
+        // doFinal(): 加密或者解密数据
+        byte[] plainText = cipher.doFinal(byteArray);
+        return plainText;
+    }
+
+    /**
+     * 返回一个keyBytes生成的privateKey对象
+     * @param keyBytes
+     * @return
+     * @throws NoSuchAlgorithmException
+     * @throws InvalidKeySpecException
+     */
+    public static PrivateKey getPrivateKey(byte[] keyBytes) throws NoSuchAlgorithmException, InvalidKeySpecException {
+        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
+        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
+        PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
+        return privateKey;
+    }
+
+    /**
+     * 用相应的key解密对应加密的问题
+     *
+     * @param keys
+     * @param byteArray
+     * @return
+     */
+    public static byte[] decryptByKey(Key keys, byte[] byteArray) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
+        // Cipher: 提供加密和解密功能的实例
+        // transformation: "algorithm/mode/padding"
+        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", provider);
+
+        // 初始化
+        cipher.init(Cipher.DECRYPT_MODE, keys);
+        // doFinal(): 加密或者解密数据
+        byte[] plainText = cipher.doFinal(byteArray);
+
+//        byte[] bytes = processData(cipher, byteArray, 1024 / 8);
+
+        return plainText;
+    }
+
+    /**
+     * 分段处理数据.
+     *
+     * @param cipher      密码算法
+     * @param dataes      数据
+     * @param segmentSize 分段大小(小于等于0不分段)
+     * @return
+     */
+    private static byte[] processData(Cipher cipher, byte[] dataes, int segmentSize) {
+        byte[] decBytes = null;
+        try {
+            ByteArrayOutputStream out = new ByteArrayOutputStream();
+            int inputLength = dataes.length;
+            int offSet = 0;
+            for (int i = 0; inputLength - offSet > 0; offSet = i * segmentSize) {
+                byte[] cache;
+                if (inputLength - offSet > segmentSize) {
+                    cache = cipher.doFinal(dataes, offSet, segmentSize);
+                } else {
+                    cache = cipher.doFinal(dataes, offSet, inputLength - offSet);
+                }
+                out.write(cache, 0, cache.length);
+                ++i;
+            }
+            decBytes = out.toByteArray();
+            out.close();
+        } catch (Exception e) {
+        }
+        return decBytes;
+    }
+
+    /**
+     * 产生public key
+     *
+     * @return public key字符串
+     */
+    public static String generateBase64Key(byte[] keys) {
+        // encodeBase64(): Encodes binary data using the base64
+        // algorithm but does not chunk the output.
+        // getEncoded():返回key的原始编码形式
+        return new String(Base64.encodeBase64(keys));
+    }
+}