本文为您介绍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登录
步骤一:使用登录认证超管账号进入超级管理员后台。
若账号无权限登录时,会出现以下界面,提示“无权限禁止访问”。请联系Quick BI运维人员添加权限。
步骤二: 选择登录系统管理->登录全局开关,开启/关闭指定的三方登录方式,保存后立即生效。
2.1. EasySSO登录对接配置
步骤一:打开登录认证配置页面
在运维中心->登录策略配置或开放平台->登录认证位置打开。两个位置打开的配置效果是一样的,下面以在运维中心打开对应页面为例,页面如下:
步骤二:添加登录策略
若您已配置过登录策略,则跳过步骤二。
每个登录策略都允许配置一套域名/IP拦截策略,用来指定访问指定域名或IP时Quick BI支持的登录方式。
登录策略配置请参见自定义企业登录门户。
步骤三:选中需要开启EasySSO登录的策略,并点击编辑。
步骤四:在【编辑策略】页面选择基础设置
步骤五:配置EasySSO三方登录
在您进行EasySSO三方登录配置前,若您未开启Quick BI账号,建议开启,原因为:1)防止三方登录设置错误后,无法登录Quick BI;2)自定义账号配置成功且能正常登录后,可根据需要关闭Quick BI账号。
Quick BI账号配置页面如下。
相关配置项请参见登录方式及说明。
开启EasySSO登录
在弹出窗口填写EasySSO的配置信息
其中,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 |
步骤六:保存发布
保存发布后立即生效,请慎重操作。
推荐新建无痕模式窗口或者打开其他浏览器测试登录配置是否成功,以防退出登录后由于登录配置错误导致无法登录。
3. 登录验证
在您完成EasySSO登录对接配置后,请访问Quick BI服务地址,并点击EasySSO登录,进行登录验证。
为了防止其他因素干扰,推荐新建无痕窗口用来测试登录。
需要注意的是所有的无痕窗口共用cookies,通过关闭窗口清空登录态时需要保证所有无痕窗口被关闭。
登录对接成功效果:当您登录后,出现以下页面,则说明已对接成功。 抛错原因是您当前登录的三方账号还未同步到Quick BI组织中,鉴权不通过,此时,您需要进行三方账号同步,请参见独立部署:三方账号同步方案。
4. 登录常见问题
4.1 AE0580800018 权限不足禁止访问,请联系组织管理员添加到具体组织
无组织用户默认无法访问Quick BI,需要先将三方账号添加到Quick BI,请参见独立部署:三方账号同步方案。
4.2. Quick BI没有调用登录态校验接口
跨域场景下,回跳到Quick BI的链接中没有ticket或者ticket参数名/格式错误。
同域场景下
cookies的域名和Qucik BI的域名没有满足同源。
cookies的名称和策略中配置的[登录态名称]不一致。
cookies的属性设置问题:
HttpOnly开启后HTTP无法获取HTTPS的cookie。
SameSite属性设置不为None。
4.3. Quick BI请求三方接口失败,例如获取登录态或者用户信息失败
请联系运维同学查看日志报错。
协议对接说明
1. 前提条件
三方在登录时返回的自身的userId,accountName和nick必须保持唯一性。
2. 流程图
3. 流程说明(重要)
当文中含有需要关键词时,您需要按照协议流程开发您的认证中心以适配EasySSO登录。
前置步骤:您需要在EasySSO登录对接配置中首先取到我们生成的公钥并进行保存。
用户发起对quickBI的访问,如果Quick BI已经是登录态,则直接可以访问Quick BI
如果用户发起对Quick BI的访问时,Quick BI没有登录态的话,会跳转到用户认证中心登录页,即EasySSO登录对接配置中的登录地址
在跳转到登录中心登录页后,如果当前认证中心已有登录态,需要跳转回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
当跳转回Quick BI时,Quick BI会根据私钥解密您的加密信息,解密之后会将,您的账户信息登入到Quick BI系统中
在跳转到登录中心登录页后,如果当前认证中心没有登录态,则您需要设计在您的认证中心登录后携带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)