文档

EasySSO协议及配置说明

更新时间:

本文为您介绍EasySSO对接协议及配置说明。

说明

独立部署版本支持对接EasySSO协议,对接前请联系Quick BI运营负责人

背景信息

为提升非标登录协议对接的效率,助力企业高效完成单点登录集成,Quick BI全新打造了EasySSO登录协议。EasySSO是Quick BI自定义的一套三方SSO对接方案,主要针对客户自有账户登录系统中没有提供标准的行业登录规范(例如:OAuth2/SAML/LDAP等协议)的场景使用。只需少量开发,就能使Quick BI简便的完成与客户自有系统间的登录对接,快速投入业务使用。

EasySSO与标准SSO对接方案各有优势:

  • EasySSO对接更加方便快捷,对接成本低,对接效率更加快速。

  • 标准SSO对接更加严谨,安全性更加高(具体请查阅方案描述小节)。

您可以针对您的使用场景来进行选型。

应用场景

客户账户系统需根据Quick BI的协议说明提供相关功能,实现以下场景:

  • 支持跳转后登录态的判断,用户信息的加密传输。

  • 支持跳转后登录态的注销。

快速开始

1. 接入前准备

1.1 前置依赖

用户按照协议对接说明完成自有账号认证系统侧的开发

2. 在Quick BI进行对接配置

2.1 开启三方SSO登录

步骤一:使用登录认证超管账号进入超级管理员后台。

image.png

若账号无权限登录时,会出现以下界面,提示“无权限禁止访问”。请联系Quick BI运维人员添加权限。

image.png

步骤二: 选择登录系统管理->登录全局开关,开启/关闭指定的三方登录方式,保存后立即生效。

image.png

2.1. EasySSO登录对接配置

步骤一:打开登录认证配置页面

在运维中心->登录策略配置或开放平台->登录认证位置打开。两个位置打开的配置效果是一样的,下面以在运维中心打开对应页面为例,页面如下:

image.png

步骤二:添加登录策略

若您已配置过登录策略,则跳过步骤二。

每个登录策略都允许配置一套域名/IP拦截策略,用来指定访问指定域名或IP时Quick BI支持的登录方式。

登录策略配置请参见自定义企业登录门户

步骤三:选中需要开启EasySSO登录的策略,并点击编辑。

image.png

步骤四:在【编辑策略】页面选择基础设置

image.png

步骤五:配置EasySSO三方登录

在您进行EasySSO三方登录配置前,若您未开启Quick BI账号,建议开启,原因为:1)防止三方登录设置错误后,无法登录Quick BI;2)自定义账号配置成功且能正常登录后,可根据需要关闭Quick BI账号。

  • Quick BI账号配置页面如下。

相关配置项请参见登录方式及说明

image.png

  • 开启EasySSO登录image.png

  • 在弹出窗口填写EasySSO的配置信息image.png

其中,EasySSO协议相关的配置项及说明如下:

配置项

是否必填

说明

参考值

系统名称

对接的系统名称,用于在登录项的按钮组标题显示。

三方系统SSO

系统图标

对接的系统图标,用于在登录项中显示图标,最大32KB。

登录地址

三方系统登录认证地址。当Quick BI跳转到此地址时,如有登录态需加密跳转回Quick BI

http://dev.sso.aliyun.test:XXXX/login.htm

登出地址

跳转到此地址后,能够退出当前登录的用户

http://dev.sso.aliyun.test:XXXX/logout.do

公钥

由“生成RSA KEY”按钮点击后生成

令牌过期时间

三方提供的开放接口,

用于获取登录态用户信息。GET 方法。

60

登录失效时间

指定登录态Session的失效时间,失效后,重新发起登录校验。单位秒,默认86400。

86400

步骤六:保存发布

重要

保存发布后立即生效,请慎重操作。

推荐新建无痕模式窗口或者打开其他浏览器测试登录配置是否成功,以防退出登录后由于登录配置错误导致无法登录。

image.png

3. 登录验证

在您完成EasySSO登录对接配置后,请访问Quick BI服务地址,并点击EasySSO登录,进行登录验证。

image.png

为了防止其他因素干扰,推荐新建无痕窗口用来测试登录。

需要注意的是所有的无痕窗口共用cookies,通过关闭窗口清空登录态时需要保证所有无痕窗口被关闭。

登录对接成功效果:当您登录后,出现以下页面,则说明已对接成功。 抛错原因是您当前登录的三方账号还未同步到Quick BI组织中,鉴权不通过,此时,您需要进行三方账号同步,请参见独立部署:三方账号同步方案

image.png

4. 登录常见问题

4.1 AE0580800018 权限不足禁止访问,请联系组织管理员添加到具体组织

无组织用户默认无法访问Quick BI,需要先将三方账号添加到Quick BI,请参见独立部署:三方账号同步方案

image..png

4.2. Quick BI没有调用登录态校验接口

  1. 跨域场景下,回跳到Quick BI的链接中没有ticket或者ticket参数名/格式错误。

  2. 同域场景下

    1. cookies的域名和Qucik BI的域名没有满足同源。

    2. cookies的名称和策略中配置的[登录态名称]不一致。

    3. cookies的属性设置问题:

      1. HttpOnly开启后HTTP无法获取HTTPS的cookie。

      2. SameSite属性设置不为None。

4.3. Quick BI请求三方接口失败,例如获取登录态或者用户信息失败

请联系运维同学查看日志报错。


协议对接说明

1. 前提条件

三方在登录时返回的自身的userId,accountName和nick必须保持唯一性。

2. 流程图

image.png

3. 流程说明(重要)

当文中含有需要关键词时,您需要按照协议流程开发您的认证中心以适配EasySSO登录。

前置步骤:您需要在EasySSO登录对接配置中首先取到我们生成的公钥并进行保存。

  1. 用户发起对quickBI的访问,如果Quick BI已经是登录态,则直接可以访问Quick BI

  2. 如果用户发起对Quick BI的访问时,Quick BI没有登录态的话,会跳转到用户认证中心登录页,即EasySSO登录对接配置中的登录地址

  3. 在跳转到登录中心登录页后,如果当前认证中心已有登录态,需要跳转回Quick BI,并携带当前登录中心的用户信息。Quick BI的需要的用户信息如下

参数名

参数类型

是否必选

说明

accountName

String

用户账户名

accountId

String

用户账户id

nick

String

昵称

timestamp

Integer

时间戳(单位秒)

需要将您的参数以组合为JSON字符串,并使用rsa进行加密,加密后的二进制数据以Base64编码,rsa的公钥即为EasySSO登录对接配置中取得的公钥。

需要组合的JSON字符串格式

{"accountName":"zhangsan","accountId":"08092122","nick":"zhangsan","timestamp":1697018710}

需要加密后的字符串格式样例

d2fvB/5n4IHFPOMhk4vVCJOlqzVf+fKXDYuhUJQfHpTo7uxNvdQPhs+XsDdpVgbRZkapn9WvqEUkN3FvtW5VkCOZGw9pudSph4D2USiVm5/QxH7oYSlp72B/CXJAt3BDAkUskUaMzmCrKLvnQaXLgZ4qsUmuMVC5klkS9N6NQiU=

下一步您需要将加密后的字符串urlencode后,以URL参数的形式添加您希望跳转回到的Quick BI的指定页面,参数值需要指定为loginToken,例如

https://myquickbi.com/home?loginToken=d2fvB%2F5n4IHFPOMhk4vVCJOlqzVf%2BfKXDYuhUJQfHpTo7uxNvdQPhs%2BXsDdpVgbRZkapn9WvqEUkN3FvtW5VkCOZGw9pudSph4D2USiVm5%2FQxH7oYSlp72B%2FCXJAt3BDAkUskUaMzmCrKLvnQaXLgZ4qsUmuMVC5klkS9N6NQiU%3D
  1. 当跳转回Quick BI时,Quick BI会根据私钥解密您的加密信息,解密之后会将,您的账户信息登入到Quick BI系统中

  2. 在跳转到登录中心登录页后,如果当前认证中心没有登录态,则您需要设计在您的认证中心登录后携带loginToken跳转回Quick BI的流程。loginToken的生成方式与第3步中的一致

4. 代码示例

4.1 构建且加密用户信息

public class EasySSOController {

    @Data
    class LoginTokenModel {
        private String accountName;

        private String accountId;

        private String nick;

        private Integer timestamp;
    }

    @RequestMapping(value = "/login")
      public String easySso(HttpServletRequest request, HttpServletResponse 
 response) {
        //TODO需要用您当前登录的账户信息给LoginTokenModel赋值
        LoginTokenModel loginToken = JSONObject.toJSONString(loginTokenModel);
        PublicKey publicKey;
        try {
            publicKey = RSAUtil.restorePublicKey(Base64Utils.decodeFromString(addition));
        } catch (Exception e) {
            e.printStackTrace();
            return "错误的公钥";
        }
        byte[] bytes = RSAUtil.rsaEncode(publicKey, loginToken.getBytes());
        String loginTokenRet = Base64Utils.encodeToString(bytes);

        referer = "https://myquickbi.com/home?loginToken="+loginTokenRet;
        //跳转
        response.setStatus(302);
        response.setHeader("location", referer);
        return "redirect:"+referer;
    }
}

4.2 RSAUtil加密工具案例

public class RSAUtil {

    public static final String KEY_ALGORITHM = "RSA";

    /**
     * 填充算法
     */
    public static final String CIPHER_ALGORITHM = "RSA/ECB/PKCS1Padding";
    public static final String PUBLIC_KEY = "publicKey";
    public static final String PRIVATE_KEY = "privateKey";

    /**
     * RSA密钥长度默认是2048
     */
    public static final int KEY_SIZE = 2048;

    /**
     * 生成密钥对。
     *
     * @return
     */
    public static Map<String, byte[]> generateKeyBytes() {

        try {
            KeyPairGenerator keyPairGenerator = KeyPairGenerator
                    .getInstance(KEY_ALGORITHM);
            keyPairGenerator.initialize(KEY_SIZE);
            KeyPair keyPair = keyPairGenerator.generateKeyPair();
            RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
            RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();

            Map<String, byte[]> keyMap = new HashMap<>(4);
            keyMap.put(PUBLIC_KEY, publicKey.getEncoded());
            keyMap.put(PRIVATE_KEY, privateKey.getEncoded());
            return keyMap;
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取公钥
     *
     * @param keyBytes
     * @return
     */
    public static PublicKey restorePublicKey(byte[] keyBytes) {
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyBytes);
        try {
            KeyFactory factory = KeyFactory.getInstance(KEY_ALGORITHM);
            return factory.generatePublic(x509EncodedKeySpec);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取私钥
     *
     * @param keyBytes
     * @return
     */
    public static PrivateKey restorePrivateKey(byte[] keyBytes) {
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(keyBytes);
        try {
            KeyFactory factory = KeyFactory.getInstance(KEY_ALGORITHM);
            return factory.generatePrivate(pkcs8EncodedKeySpec);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 用公钥加密
     *
     * @param key
     * @param plainText
     * @return
     */
    public static byte[] rsaEncode(PublicKey key, byte[] plainText) {
        try {
            Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, key);
            return cipher.doFinal(plainText);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 用私钥解密
     *
     * @param key
     * @param encodedText
     * @return
     */
    public static String rsaDecode(PrivateKey key, byte[] encodedText) {
        try {
            Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, key);
            return new String(cipher.doFinal(encodedText));
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }
}

  • 本页导读 (0)