sso组件(单点登录)

一、准备工作

1.确认动态域名

​ 请首先确认你从得助平台获取的动态域名,得助平台提供的动态域名的格式形如: https://xxx.dezhuyun.com 。 本文档后续章节的例子中使用的动态域名为https://{您的专属域名}。

2.sso配置(获取鉴权Token)

1)请使用主账号登录得助后台,进入SSO配置页面,路径:设置-->系统对接-->第三方账号登录,填写相关的SSO配置。如下图:

登录URL:填写第三方平台的登录页地址;

默认部门:选择一个部门(得助系统中不存在的账号首次sso登录成功后用户在得助后台的部门);

默认角色:选择一个角色(得助系统中不存在的账号首次sso登录成功后用户在得助后台的角色);

退出URL:在得助后台退出后要跳转的URL;

2)填写完成并点击“保存”后,配置页面将显示由得助后台系统为你生成的鉴权token,请妥善保管该token,后续接入开发会使用该token来加密登录信息。

3.sso整体流程(适用于页面访问单点登录,不适应于单独拨号盘对接)

用户访问得助域名

-->页面自动跳转到第三方平台“登录URL”

-->用户填写第三方平台的用户名密码进行登录

-->第三方平台后台调用sso登录接口获取authorization(在header中),返回给第三方平台前端页面

-->第三方平台前端页面使用window.location.href方式跳转到得助平台,例如: window.localtion.href = 'https://{您的专属域名}?token=' + res.authorization

二、开发步骤

​ 此处假设你已经完成“准备工作”一节中所有的要求,并已准备了一个Web系统用于开发。

1.单点登录接口调用

注意:为了您系统的安全性,请使用后台系统对接调用(应避免使用js从浏览器端直接调用本接口)。

你的Web页面需要通过调用得助平台提供的SSO登录接口,来完成SSO登录功能,以下是SSO登录接口说明:

接口地址 https://{您的专属域名}/basic/user/sso/login 接口地址的域名部分【mydomain】需要填写你从得助平台获取的动态域名
方法 POST 【注意参数是query参数(非body)】
接口参数 (query参数) data 登录数据的加密字符串。data参数对应的值是对一个Json字符串使用rsa算法加密后生成的字符串(该json字符串字段见下方表格)。rsa使用的加密密钥,就是准备工作一节中获取到的鉴权token,为保证鉴权token不被窃取,建议在你的web后台实现接口,完成加密过程。
接口参数 (query参数) timestamp 当前时间戳(注意必须与data参数中的timestamp的值相同

data参数字段如下:

字段code 是否必填 描述
thirdpartAccount 你使用的Web系统的登陆账号唯一标识(若没有,可使用手机号或邮箱)
email 邮箱
phone 手机号
empno 工号(若没有,可同手机号)
timestamp 当前时间戳,注意必须与接口query参数中的timestamp的值相同

注意:data和timestamp参数登录成功一次以后,就不能再使用了,后续重新登录需要使用新的timestamp和data;

接口调用成功后,会以json格式返回登陆信息。返回的header中含有字段名为authorization的参数。

2.登录成功后跳转页面(适用于页面访问单点登录,不适应于单独拨号盘对接)

在获取到authorization参数后,即可通过href链接的方式直接跳转到得助平台,跳转链接需增加token参数, 值就是返回Json中authorization字段的值,跳转链接生成示例:

window.localtion.href = 'https://{您的专属域名}?token=' + res.authorization

此时,由于之前已经通过SSO登录接口登录了得助平台,跳转完成后就会以已登录的状态进入得助平台管理界面,SSO登录成功!

3.单点登录接口调用Demo及工具类

鉴权Token:即示例代码中的publicKey, 详见:sso配置(获取鉴权Token)

​ 鉴权token属于敏感数据,因此强烈建议你避免在前端js中使用鉴权token完成登录数据的加密,更好的方式是将鉴权token安全存储在你的web后台能访问的位置,并在你的web后台中实现一个登录数据加密接口来完成数据加密。 该接口只完成RSA加密,RSA是公开的标准加密算法,因此具体的实现由你web后台采用的技术框架而定,如在开发过程中遇到阻碍,可直接联系得助平台获取技术支持。

完整demo路径:https://open-docs.dezhuyun.com/src/dz-openapi-demo.zip

data参数加密demo

long timestamp = System.currentTimeMillis();
        JSONObject jsonObject = new JSONObject();

        jsonObject.put("email","hucpoo@163.com");
        jsonObject.put("phone","17511698701");
        jsonObject.put("empno","000001");
        jsonObject.put("thirdpartAccount","hucpoo@163.com");
        jsonObject.put("timestamp",timestamp);

// 页面上的token
        String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDidXrjGBioBdTrdPqRm6SHdpoQ7NREZrkMNBF5NZfPaDijF+bg2OJKIOFaOJ1P0fcc/vR24yB/enr6/jMs/atnLPQHbkkXwGkYRfHqcG/DfoMRnizJCbYCK4vyJy/FcQiwJI19EwX9VjKtdqYKQe79Mcy/ZhyXCoZMoi87Kfn4BwIDAQAB";
        String result = RSAUtil.rsaEncrypt(jsonObject.toString(), publicKey);

        RestTemplate restTemplate = new RestTemplate();

        String url = "https://gateway-worldtedu.51ima.com/basic/user/sso/login";

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

        MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
        params.add("data", result);
        params.add("timestamp", String.valueOf(timestamp));

        HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(params, headers);

        ResponseEntity<JSONObject> jsonObjectResponseEntity = restTemplate.postForEntity(url, request, JSONObject.class);
        System.out.println(jsonObjectResponseEntity.getStatusCode());
        System.out.println(jsonObjectResponseEntity.getHeaders());

RSA加密类代码如下:

import java.io.ByteArrayOutputStream;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.Cipher;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;

public class RSAUtil {
    /**
     * 密钥长度(bit)
     */
    // FIXME 按公司规范,秘钥长度需要大于2048
    public static final int KEY_LENGTH = 1024;

    public static final int MAX_ENCRYPT_BLOCK = 117;
    /**
     * <p>
     * 单次解密最大密文长度,这里仅仅指1024bit 长度密钥
     * </p>
     *
     * @see #MAX_ENCRYPT_BLOCK
     */
    public static final int MAX_DECRYPT_BLOCK = 128;

    /**
     * 加密算法
     */
    public static final String ALGORITHM_RSA = "RSA";

    /**
     * 算法/模式/填充
     */
    public static final String CIPHER_TRANSFORMATION_RSA = "RSA/ECB/PKCS1Padding";

    /**
     * 签名算法
     */
    public static final String SIGN_ALGORITHMS = "SHA1WithRSA";

    /**
     * UTF-8字符集
     **/
    public static final String CHARSET_UTF8 = "UTF-8";

    /**
     * GBK字符集
     **/
    public static final String CHARSET_GBK = "GBK";

    public static final String CHARSET = CHARSET_UTF8;

    /**
     * 得到公钥
     *
     * @param key     密钥字符串(经过base64编码)
     * @param charset
     * @throws Exception
     */
    public static PublicKey getPublicKey(String key, String charset)
            throws Exception {
        byte[] keyBytes = Base64.decodeBase64(key.getBytes(charset));

        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM_RSA);
        PublicKey publicKey = keyFactory.generatePublic(keySpec);
        return publicKey;
    }

    /**
     * 得到私钥
     *
     * @param key     密钥字符串(经过base64编码)
     * @param charset
     * @throws Exception
     */
    public static PrivateKey getPrivateKey(String key, String charset)
            throws Exception {
        byte[] keyBytes;
        keyBytes = Base64.decodeBase64(key.getBytes(charset));

        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM_RSA);
        PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
        return privateKey;
    }

    /**
     * 得到密钥字符串(经过base64编码)
     *
     * @return
     */
    public static String getKeyString(Key key) throws Exception {
        byte[] keyBytes = key.getEncoded();
        String s = new String(Base64.encodeBase64(keyBytes), CHARSET);
        return s;
    }

    /**
     * 公钥加密
     *
     * @param content   待加密内容
     * @param publicKey 公钥
     * @param charset   字符集,如UTF-8, GBK, GB2312
     * @return 密文内容
     * @throws Exception
     */
    public static String rsaEncrypt(String content, String publicKey,
                                    String charset) throws Exception {
        try {
            PublicKey pubKey = getPublicKey(publicKey, charset);
            Cipher cipher = Cipher.getInstance(CIPHER_TRANSFORMATION_RSA);
            cipher.init(Cipher.ENCRYPT_MODE, pubKey);
            byte[] data = StringUtils.isEmpty(charset) ? content.getBytes()
                    : content.getBytes(charset);
            int inputLen = data.length;
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            int offSet = 0;
            byte[] cache;
            int i = 0;
            // 对数据分段加密
            while (inputLen - offSet > 0) {
                if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
                    cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
                } else {
                    cache = cipher.doFinal(data, offSet, inputLen - offSet);
                }
                out.write(cache, 0, cache.length);
                i++;
                offSet = i * MAX_ENCRYPT_BLOCK;
            }
            byte[] encryptedData = Base64.encodeBase64(out.toByteArray());
            out.close();

            return StringUtils.isEmpty(charset) ? new String(encryptedData)
                    : new String(encryptedData, charset);
        } catch (Exception e) {
            throw new Exception(
                    "error occured in rsaEncrypt: EncryptContent = " + content
                            + ",charset = " + charset, e);
        }
    }

    /**
     * 公钥加密
     *
     * @param content   待加密内容
     * @param publicKey 公钥
     * @return 密文内容
     * @throws Exception
     */
    public static String rsaEncrypt(String content, String publicKey)
            throws Exception {
        return rsaEncrypt(content, publicKey, "utf8");
    }

    /**
     * 私钥解密
     *
     * @param content    待解密内容
     * @param privateKey 私钥
     * @param charset    字符集,如UTF-8, GBK, GB2312
     * @return 明文内容
     * @throws Exception
     */
    public static String rsaDecrypt(String content, String privateKey,
                                    String charset) throws Exception {
        try {
            PrivateKey priKey = getPrivateKey(privateKey, charset);
            Cipher cipher = Cipher.getInstance(CIPHER_TRANSFORMATION_RSA);
            cipher.init(Cipher.DECRYPT_MODE, priKey);
            byte[] encryptedData = StringUtils.isEmpty(charset) ? Base64
                    .decodeBase64(content.getBytes()) : Base64
                    .decodeBase64(content.getBytes(charset));
            int inputLen = encryptedData.length;
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            int offSet = 0;
            byte[] cache;
            int i = 0;
            // 对数据分段解密
            while (inputLen - offSet > 0) {
                if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
                    cache = cipher.doFinal(encryptedData, offSet,
                            MAX_DECRYPT_BLOCK);
                } else {
                    cache = cipher.doFinal(encryptedData, offSet, inputLen
                            - offSet);
                }
                out.write(cache, 0, cache.length);
                i++;
                offSet = i * MAX_DECRYPT_BLOCK;
            }
            byte[] decryptedData = out.toByteArray();
            out.close();

            return StringUtils.isEmpty(charset) ? new String(decryptedData)
                    : new String(decryptedData, charset);
        } catch (Exception e) {
            throw new Exception("error occured in rsaDecrypt: EncodeContent = "
                    + content + ",charset = " + charset, e);
        }
    }

    /**
     * 私钥解密
     *
     * @param content    待解密内容
     * @param privateKey 私钥
     * @return 明文内容
     * @throws Exception
     */
    public static String rsaDecrypt(String content, String privateKey)
            throws Exception {
        return rsaDecrypt(content, privateKey, "utf8");
    }

    /**
     * 获得密钥对
     *
     * @return
     * @throws NoSuchAlgorithmException KeyPair
     * @Title creatKeyPair
     * @Description TODO
     */
    public static KeyPair creatKeyPair() throws NoSuchAlgorithmException {
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
        // 密钥位数
        keyPairGen.initialize(KEY_LENGTH);
        // 密钥对
        KeyPair keyPair = keyPairGen.generateKeyPair();
        return keyPair;
    }
}

results matching ""

    No results matching ""