单点登录第三方系统集成
注:版本 V7. 10.1023 以及以上版本可用
一、概念
业务系统的专业性、系统间为了降低耦合性,单系统被拆分到若干子系统。

什么是单点登录
简单来讲,如下图所示,企业用户登录到Portal门户系统,只需要登录一次,就可以访问所有相互信任的应用系统(CRM、Email、ERP等等)。

二、功能设计
流程图

三、系统集成
3.1 系统配置
登录系统进入后台,点击“系统管理”->“系统参数”->“单点登录”->“第三方系统配置”,“新增”第三方系统配置:

密钥规格
RSA2公钥私钥,长度2048bit,私钥格式:PKCS#1,公钥格式:PKCS#8。
密钥生成
RSA在线生成,访问 http://www.metools.info/code/c80.html。
- 生成密钥长度为2048,密钥格式PKCS#1,密钥密码不设置,点击“生成密钥对”。

将公钥密钥格式改为PKCS#8,访问 http://www.metools.info/code/c85.html。
将以上生成的公钥整体粘贴到如下网址的输入框,选择“公钥”,格式为“PKCS1转PKCS8”,点击“转换”。
3.2 集成接口
集成功能
① 渲染单点登录的第三方系统列表;
② 向S2平台获取第三方系统RSA加密公钥,妥善保存在本地用于token加密;
③ 点击第三方子系统链接,获取该系统的单点认证路由地址;
认证路由地址:回调地址 + systemCode + token(URL编码)
http://crm.com/sso/callback?token=FED5A255A6A5BBEEC6AF3E316ED7B50FCA8F4FF5C9E287BEF145751FF5A22E1CA49F65DEE647DA404496FB8932E9A01B252F85C988B32115EFDCB56E2AE69777
使用公钥加密 token后,得到如下认证路由地址:
http://crm.com/sso/callback?systemCode=crm& token=EJyO6nlEvruA5AoS55V9B45smOZAHSIpPOx8adnl%2FA79cIi4Ty8i%2BXDh9rpGl88Z9uD16LQIxpnKxjWBJWiVbQ7bzSzxmUuAbP1ii7EYSY6OYz7qRXhIVhcD2v2F8pfzAeGWEd0fFHSBYc1E8gNeJEBULFBoSbiINIuE5ZDs2Bhl7NeFLhaSde6dsRk1O%2BIYUvf4G4xwIkWvh3cVfjmuXDAj8NmunGBxcdj4Hx9GT2pBiEJ%2FC98ytR1hOaAMB%2FyBr%2FIIgVqhpfX2uWBBpXGLSgHIT0OCSi9LAh5axigGxzJScgQOQ7q1O8E2txzH8DBTgodj9APY6IcI0zBBotMcgA%3D%3D
④ 第三方系统单点认证登录
首先使用私钥解密token,解析密文,获取认证信息。
集成接口
- 第三方系统列表
| 接口名称 | api/System/GetThirdParties | |||
|---|---|---|---|---|
| HTTP方法 | GET | |||
| 入参 | 类型 | 成员 | 含义 | 类型 |
| - | - | |||
| 出参 | BaseResultModel | Status | 0:失败;1:成功;3:异常 | int |
| Message | 错误提示信息 | String | ||
| Code | HTTPCode | String | ||
| Result | 第三方系统信息 | List<ThirdPartyInfo> |
- 获取第三方第三方系统单点认证路由链接
| 接口名称 | api/System/GetAuthCode | |||
|---|---|---|---|---|
| HTTP方法 | GET | |||
| 入参 | 类型 | 成员 | 含义 | 类型 |
| userCode | - | 用户登录名 | String | |
| systemCode | - | 第三方系统编码 | String | |
| 出参 | BaseResultModel | Status | 0:失败;1:成功;3:异常 | int |
| Message | 错误提示信息 | String | ||
| Code | HTTPCode | String | ||
| Result | 单点认证路由链接 | String |
- 解析认证Token、获取用户信息接口
| 接口名称 | api/OrganizationExt/SSOLogin/{systemCode} | |||
|---|---|---|---|---|
| HTTP方法 | POST | |||
| 入参 | 类型 | 成员 | 含义 | 类型 |
| token | - | 认证Token | String ,从body传值 | |
| systemCode | - | 第三方系统编码 | String,从url传值 | |
| 出参 | BaseResultModel | Status | 0:失败;1:成功;3:异常 | int |
| Message | 错误提示信息 | String | ||
| Code | HTTPCode | String | ||
| SSOLoginReponse | Result: 解析结果Message:错误信息UserInfo:用户信息 | booleanstringUserInfo |
3.3 代码 Java RSA 公钥加密代码:
import javax.crypto.Cipher;
import java.security.KeyFactory;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
public class Rsa {
// RSA2 2048 PKCS8 private static String publicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnDSqooST+PfiWyVr7454" +
"E9jAV1fHHauIP2rAf8AFMmWhZCbd3R4jpPTsEFDw7gftKHB4hijaWWOTQS8JQJe1" +
"+R/cMLUQ6rBAQWuA1iMYZLRo3N89SZyUgcTk+0sD0WxcCAC8uwJbynfgnQXZIav+" +
"/4K3SUA774Rg05Xmckt1UorF1crhHWgsIdKxuWj+oN1W1bK2na1thCA9aMTP83Y7" +
"3fiBHayrZo0YetKmGxI1sIJ/iQv/tQNAoXD7Y49yHPmv2keNf8btt75a2fvTNX0J" +
"f2oztOCkYzgmAIzKHkxe9oxUZGVzLZksojhJhr+/7mT42rUSnugwk/QmcGJhq7cm" +
"sQIDAQAB";
public static void main(String[] args) throws Exception {
String token = "FED5A255A6A5BBEEC6AF3E316ED7B50FCA8F4FF5C9E287BEF145751FF5A22E1CA49F65DEE647DA404496FB8932E9A01B252F85C988B32115EFDCB56E2AE69777";
byte[] messageEn = encrypt(token.getBytes(), publicKey);
token = new String(Base64.getEncoder().encode(messageEn));
System.out.println("加密后的字符串:" + token);
}
public static byte[] encrypt(byte[] str, String publicKey) throws Exception
{
// base64编码的公钥
byte[] decoded = Base64.getDecoder().decode(publicKey);
RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA")
.generatePublic(new X509EncodedKeySpec(decoded));
// RSA加密
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
return cipher.doFinal(str);
}
}