æ¦å¿µ
åç¹ç»å½ï¼Single Sign-Onï¼SSOï¼æ¯ä¸ç§èº«ä»½éªè¯æå¡ï¼å 许ç¨æ·ä½¿ç¨å个æ è¯æ¥ç»å½å¤ä¸ªåºç¨ç¨åºæç³»ç»ãå¦ä¸å¾æ示ï¼ç¨æ·åªéè¦ç¨æ·å/å¯ç ç»éä¸æ¬¡å°±å¯ä»¥è®¿é®ç³»ç»Aãç³»ç»Båç³»ç»Cã
å¨ä¼ ç»çç»å½æ¹å¼ä¸ï¼ç¨æ·å¿ 须为æ¯ä¸ªåºç¨ç¨åºæç³»ç»æä¾ä¸åçåæ®åå¯ç ãå¦ä¸å¾æ示ï¼ç¨æ·è®¿é®ç³»ç»Aãç³»ç»Båç³»ç»Cé½å¿ é¡»ç¨ç¨æ·å/å¯ç ç»éã
è¿ç§æ¹å¼æ¢ä¸æ¹ä¾¿ä¹å®¹æ被æ»å»è å©ç¨ï¼è SSO 解å³äºè¿ä¸ªé®é¢ï¼ä½¿å¾ç¨æ·åªééè¿ä¸æ¬¡èº«ä»½éªè¯å°±å¯ä»¥æ ç¼å°è®¿é®å¤ä¸ªåºç¨ç¨åºæç³»ç»ï¼ä»èæé«äºç¨æ·ä½éªç便å©æ§åå®å ¨æ§ã
åç¹ç»éçä¼ç¹
- ç¨æ·ä½éªæ¹åï¼ç¨æ·åªéè¦ç»å½ä¸æ¬¡ï¼å°±å¯ä»¥è®¿é®å¤ä¸ªç³»ç»æåºç¨ç¨åºï¼ä¸éè¦éå¤è¾å ¥ç¨æ·ååå¯ç ãè¿å¯ä»¥å¤§å¤§æé«ç¨æ·çå·¥ä½æçã
- å®å ¨æ§å¢å¼ºï¼åç¹ç»éå¯ä»¥æä¾æ´é«çº§å«çå®å ¨æ§ï¼å 为ç¨æ·åªéè¦å¨ä¸ä¸ªç³»ç»ä¸è¿è¡èº«ä»½éªè¯ï¼å ¶ä»ç³»ç»å°±å¯ä»¥å ±äº«è¿ä¸ªèº«ä»½éªè¯ä¿¡æ¯ãè¿å¯ä»¥ææå°é²æ¢é»å®¢å ¥ä¾µå¤ä¸ªç³»ç»ã
- 管çæ´æ¹ä¾¿ï¼åç¹ç»éå¯ä»¥ç®å管çåçå·¥ä½ï¼å 为å®å¯ä»¥éä¸ç®¡çç¨æ·åæéã管çåå¯ä»¥å¨ä¸ä¸ªç³»ç»ä¸ç®¡çå¤ä¸ªç³»ç»çç¨æ·åæéï¼è¿æ ·å¯ä»¥æ´æ¹ä¾¿å°è¿è¡ç®¡çåç»´æ¤ã
åç¹ç»éçå®ç°æ¹å¼
- å ±äº«èº«ä»½éªè¯ï¼å¤ä¸ªç³»ç»å ±äº«ä¸ä¸ªèº«ä»½éªè¯ç³»ç»ï¼ç¨æ·åªéè¦å¨ä¸ä¸ªç³»ç»ä¸è¿è¡èº«ä»½éªè¯ï¼å°±å¯ä»¥è®¿é®ææç³»ç»ãè¿ç§æ¹å¼éè¦å»ºç«ä¸ä¸ªå ±äº«ç身份éªè¯ç³»ç»ï¼è¿æ ·å¯ä»¥ä¿è¯ç¨æ·ä¿¡æ¯çå®å ¨æ§ã
- 代ç身份éªè¯ï¼ä¸ä¸ªç³»ç»ä»£è¡¨å ¶ä»ç³»ç»è¿è¡èº«ä»½éªè¯ï¼ç¨æ·å¨ç»å½æ¶è¾å ¥ç¨æ·ååå¯ç ï¼ç¶åå ¶ä»ç³»ç»ä¼ä»£è¡¨ç¨æ·è¿è¡èº«ä»½éªè¯ãè¿ç§æ¹å¼éè¦å»ºç«ä¸ä¸ªä»£çç³»ç»ï¼è¿æ ·å¯ä»¥ä¿è¯ç¨æ·ä¿¡æ¯çå®å ¨æ§ã
- åºäºä»¤çç身份éªè¯ï¼ç¨æ·å¨ç»å½åï¼ä¼è·å¾ä¸ä¸ªä»¤çï¼è¿ä¸ªä»¤çå¯ä»¥å¨å¤ä¸ªç³»ç»ä¸è¿è¡èº«ä»½éªè¯ãè¿ç§æ¹å¼éè¦å»ºç«ä¸ä¸ªä»¤ç管çæºå¶ï¼è¿æ ·å¯ä»¥ä¿è¯ç¨æ·ä¿¡æ¯çå®å ¨æ§ã
å®æä¸
æ¶æå¾
- ç¨æ·è¾å ¥ç¨æ·å/å¯ç ç»é ServiceA ç³»ç»ï¼
- ç¨æ·ç¹å» ServiceA ç³»ç»ä¸çæ个æé®è·³è½¬å° ServiceB ç³»ç»ï¼å¨è·³è½¬æ¶éè¦å¸¦ä¸ ServiceA ç³»ç»é¢åç ticket 票æ®ï¼
- ServiceB ç³»ç»æ¿ ServiceA ç³»ç»ç ticket å»è·å ServiceA ç³»ç»çç¨æ·ä¿¡æ¯ï¼
- ServiceA ç³»ç»ä¼æ ¡éªè¯¥ ticket 票æ®ï¼ç¶åå°ç¨æ·ä¿¡æ¯è¿åç» ServiceB ç³»ç»ï¼
- ServiceB ç³»ç»æ ¹æ®ç¨æ·ä¿¡æ¯çæ token 并é带éå®åå°åè¿åç» ServiceA ç³»ç»ï¼
- ServiceA ç³»ç»å°±å¯ä»¥æ¿çè·åç token å»è®¿é® ServiceB ç³»ç»çèµæºä¿¡æ¯äºã
代ç å®ç°
æ°æ®åº
é¦å æ¯åå§åæ°æ®åºï¼ç¨æ·ãå ¬å¸ç表ä¾æ®èªå·±çå ·ä½ä¸å¡èå®ï¼æ¤å¤ä¸åèµè¿°ãæä¾å ¬å ±çåç¹ç»éä¿¡æ¯è¡¨ã
sqlå¤å¶ä»£ç CREATE TABLE `sso_client_detail` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'èªå¢ä¸»é®',
`platform_name` varchar(64) DEFAULT NULL COMMENT 'åºç¨å称',
`platform_id` varchar(64) NOT NULL COMMENT 'åºç¨æ è¯',
`platform_secret` varchar(64) NOT NULL COMMENT 'åºç¨ç§é¥',
`encrypt_type` varchar(32) NOT NULL DEFAULT 'RSA' COMMENT 'å å¯æ¹å¼ï¼AESæè
RSA',
`public_key` varchar(1024) DEFAULT NULL COMMENT 'RSAå å¯çåºç¨å
¬é¥',
`sso_url` varchar(128) DEFAULT NULL COMMENT 'åç¹ç»å½å°å',
`remark` varchar(1024) DEFAULT NULL COMMENT 'å¤æ³¨',
`create_date` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'å建æ¶é´',
`create_by` varchar(64) DEFAULT NULL COMMENT 'å建人',
`update_date` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ´æ°æ¶é´',
`update_by` varchar(64) DEFAULT NULL COMMENT 'æ´æ°äºº',
`del_flag` bit(1) NOT NULL DEFAULT b'0' COMMENT 'å é¤æ å¿ï¼0ï¼æ£å¸¸ï¼1ï¼å·²å é¤',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='åç¹ç»éä¿¡æ¯è¡¨'
æå ¥æµè¯æ°æ®
sqlå¤å¶ä»£ç INSERT INTO cheetah.sso_client_detail
(id, platform_name, platform_id, platform_secret, encrypt_type, public_key, sso_url, remark, create_date, create_by, update_date, update_by, del_flag)
VALUES(1, 'serviceA', 'A9mQUjun', 'Y6at4LexY5tguevJcKuaIioZ1vS3SDaULwOtXW63buBK4w2e1UEgrKmscjEq', 'RSA', NULL, 'http://127.0.0.1:8081/sso/url', NULL, '2023-05-23 16:55:26', 'system', '2023-05-30 13:16:16', NULL, 0);
- platform_idåplatform_secretï¼é¿Qæ¯ä½¿ç¨ apache ç commons-lang3 å ä¸çRandomStringUtils.randomAlphanumeric()æ¹æ³çæçã
- sso_urlå°±æ¯ä¸è¾¹æå°ç ServiceB ç³»ç»çå°åã
- encrypt_typeãpublic_keyå¨æ¤æ¹å¼ä¸æªä½¿ç¨ï¼å¯ä»¥å¿½ç¥ã
ç»å¿çé¿Qè¿ç»å¤§å®¶åå¤äºä¸ä¸ªæ¥å£ï¼åªéè¦ä¼ å ¥ platformName å ssoUrl å°±å¯ä»¥èªå¨çæåç¹ç»éä¿¡æ¯ã
æ¥ä¸æ¥æ们就è¿å ¥çæ£ç代ç é¨åäºï¼åå¤âssoâå³å¯è·åå®ææºç ã
A跳转B
javaå¤å¶ä»£ç /**
* com.itaq.cheetah.serviceA.controller.PortalController#jump
* titleï¼è·³è½¬ ServiceB
* <pre>
* 1. å端ç¹å»Jumpé¾æ¥è§¦åæ¤æ¥å£è°ç¨
* 2. æ¤æ¥å£çæticket并æºå¸¦çè¯·æ± ServiceB
* 2.1 ServiceBæ¿çticket请æ±ææ¹æå¡è·åç¨æ·ä¿¡æ¯
* 2.2 ServiceBè·åå°ææ¹ç¨æ·ä¿¡æ¯å¹¶è¿è¡æ°æ®åæ¥
* 2.3 ServiceBè¿åä¸ä¸ªé¾æ¥ï¼è¿æ¥ä¸å¸¦ token
* 3. éå®åå°è¿åçé¾æ¥å®ç°ç»å½
* </pre>
*
* @param req åç¹è·³è½¬è¯·æ±ä½
* @return ServiceBåç¹ç»å½å°å
*/
@PostMapping("/jumpB")
public WrapperResult<String> jump(@RequestBody @Validated SsoJumpReq req) {
log.debug("åç¹ç»å½ï¼{}", req.getPlatformName());
//1ãå¤æ该平å°å称æ¯å¦åå¨
SsoClientDetail one = iSsoClientDetailService.getOne(
new LambdaQueryWrapper<SsoClientDetail>().eq(SsoClientDetail::getPlatformName, req.getPlatformName())
);
if (Objects.isNull(one)) {
return WrapperResult.faild("ä¸åå¨çapp");
}
//2ãæ ¡éªæ¬ç³»ç»ç tokenï¼å¹¶ä»ä¸è·åç¨æ·ä¿¡æ¯
/*
* 示ä¾
* Result<Token> result = authorizationApi.checkToken(req.getToken());
*/
//3ãçæticketï¼å¹¶å°ç¨æ·ä¿¡æ¯ä¸å
¶ç»å®åå
¥redis
String ticket = UUID.randomUUID().toString().replaceAll("-", "");
UserInfo userInfo = new UserInfo();
userInfo.setId(1L);
userInfo.setUsername("é¿Q");
redisTemplate.opsForValue().set(RedisConstants.TICKET_PREFIX + ticket, userInfo, 5, TimeUnit.MINUTES);
String ssoUrl = one.getSsoUrl();
Map<String, Object> data = new HashMap<>(1);
data.put("ticket", ticket);
//4ãåéhttp请æ±ï¼æticketéè¿è®¾ç½®å¥½çssoUrlä¼ ç»ServiceB
WrapperResult<SsoRespDto> ssoRespDto = HttpRequest
.get(ssoUrl)
.queryMap(data)
.connectTimeout(Duration.ofSeconds(120))
.readTimeout(Duration.ofSeconds(120))
.execute()
.asValue(new TypeReference<WrapperResult<SsoRespDto>>() {
});
log.info("请æ±ServiceB ç»æï¼{}", JsonUtils.toPrettyString(ssoRespDto));
return WrapperResult.success(ssoRespDto.getData().getRedirectUrl());
}
Bè·å票æ®ï¼å¹¶è¯·æ±Aè·åç¨æ·ä¿¡æ¯
javaå¤å¶ä»£ç /**
* com.itaq.cheetah.serviceB.controller.SsoController#sso
* è·å票æ®ï¼å¹¶è¯·æ±ServiceA è·åç¨æ·ä¿¡æ¯
* @param ticket 票æ®
* @return è¿åå°åä¾sso跳转
* @throws JsonProcessingException å¼å¸¸
*/
@GetMapping("/url")
public WrapperResult<SsoRespDto> sso(@RequestParam("ticket") String ticket) throws JsonProcessingException {
log.info("æ¶å°ç¥¨æ®ï¼{}", ticket);
//1.æ ¹æ®ticketæ¢åServiceAç¨æ·ä¿¡æ¯
Map<String, Object> param = new HashMap<>(1);
param.put("ticket", ticket);
String ssoUrl = "http://localhost:8081/getUser";
String s = HttpRequest
.get(ssoUrl)
.queryMap(param)
.connectTimeout(Duration.ofSeconds(120))
.readTimeout(Duration.ofSeconds(120))
.execute()
.asString();
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
WrapperResult<SsoUserInfo> ssoUserInfoWrapperResult = objectMapper.readValue(s, new TypeReference<WrapperResult<SsoUserInfo>>() {
});
log.info("ticketç»å½ç»æï¼{}", new ObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(ssoUserInfoWrapperResult));
//2.è·åå°ç¨æ·ä¿¡æ¯ä¹ååæ¥å°æ¬å°æ°æ®åº
log.info("è·åç¨æ·ä¿¡æ¯åæ¥æ°æ®åº");
//3.çætoken
log.info("çætoken");
SsoRespDto respDto = new SsoRespDto();
//4ãå°ServiceAè¦è·³è½¬çå°åè¿ç»ServiceA并æºå¸¦ ServiceB çtoken
respDto.setRedirectUrl("http://localhost:8082/index?token=123456");
WrapperResult<SsoRespDto> success = WrapperResult.success(respDto);
log.info(new ObjectMapper().writeValueAsString(success));
return success;
}
Aæä¾çè·åç¨æ·ä¿¡æ¯æ¥å£
javaå¤å¶ä»£ç /**
* com.itaq.cheetah.serviceA.controller.PortalController#loginByTicket
* æ ¹æ®ç¥¨æ®è·åç¨æ·ä¿¡æ¯
* @param ticket 票æ®ä¿¡æ¯
* @return ç¨æ·ä¿¡æ¯
*/
@ApiOperation("æ ¹æ®ticketè·åç¨æ·ä¿¡æ¯")
@GetMapping("/getUser")
public WrapperResult<SsoUserInfo> loginByTicket(@RequestParam("ticket") String ticket) {
log.info("æ¶å°ç¥¨æ®ï¼{}", ticket);
UserInfo userInfo = (UserInfo) redisTemplate.opsForValue().get(RedisConstants.TICKET_PREFIX + ticket);
if (Objects.isNull(userInfo)) {
return WrapperResult.faild("æ æ³è¯å«ç票æ®ä¿¡æ¯");
}
//å¯è½ userInfo ä¸åªæå°éçç¨æ·ä¿¡æ¯ï¼æ¤å¤çç¥äºæ ¹æ®ç¨æ·idæ¥è¯¢ç¨æ·åä¼ä¸ä¿¡æ¯çè¿ç¨ï¼èªè¡ç¼åé»è¾ä»£ç å³å¯
SsoUserInfo ssoUserInfo = new SsoUserInfo();
BeanUtil.copyProperties(userInfo,ssoUserInfo);
return WrapperResult.success(ssoUserInfo);
}
æµè¯ç»æ
å®æäº
æ¶æå¾
è¿æ¬¡æä»¬ç¨ ServiceB ç³»ç»åç¹ç»é ServiceA æ¹å¼ï¼
- ç¨æ·è¾å ¥ç¨æ·å/å¯ç ç»é ServiceB ç³»ç»ï¼
- ç¨æ·ç¹å» ServiceB ç³»ç»ä¸çæ个æé®è·³è½¬å° ServiceA ç³»ç»ï¼å¨è·³è½¬æ¶éè¦å¸¦ä¸ ServiceB ç³»ç»å å¯åçç¨æ·ä¿¡æ¯ï¼
- ServiceA ç³»ç»æ¿å° ServiceB ç³»ç»å å¯åçç¨æ·ä¿¡æ¯åè¿è¡éªç¾å解å¯æä½ï¼
- ServiceA ç³»ç»å°ç¨æ·ä¿¡æ¯ä¿åå°æ¬å°å¹¶çæ token è¿åç» ServiceB ç³»ç»ï¼
- ServiceB ç³»ç»æ¿å° ServiceA ç³»ç»è¿åç token å°±å¯ä»¥è®¿é® ServiceA ç³»ç»çèµæºä¿¡æ¯äºï¼
代ç å®ç°
æ¤ç§æ¹å¼å°±ç¨å°äºä¸è¾¹æå°çæ°æ®åºä¸çencrypt_typeãpublic_keyå段ï¼å ¶ä¸ public_key æ¯ ServiceA ç» ServiceB æä¾çã为äºæ¼ç¤ºæ¹ä¾¿ç´æ¥å¨application.ymlä¸è¿è¡é ç½®ã
Bçé ç½®
ymlå¤å¶ä»£ç #æ¬æå¡çappIdåappSecretä¿¡æ¯ï¼è¯¥é
ç½®ç±serviceAæä¾
appId: A9mQUjun
appSecret: Y6at4LexY5tguevJcKuaIioZ1vS3SDaULwOtXW63buBK4w2e1UEgrKmscjEq
encrypt:
#å å¯æ¹å¼ RSA | AES
type: RSA
#该é
ç½®æ¯serviceAåç¹ç»éserviceBç¨å°çï¼æ¤å¤æ¯serviceBåç¹serviceA,æ以ç¨ä¸å°
#å¦æéæ©é对称å å¯ï¼éè¦ä½¿ç¨è¯¥é
ç½®ï¼æ¬æå¡çå
¬ç§é¥ä¿¡æ¯ï¼è¯¥é
ç½®ç±serviceBèªå·±çæï¼å¹¶å°publicKeyç»serviceA
rsa:
publicKey: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0KLYE2Tv4qx/duxu8Qvq5ZN58yEjj/uwsxfs96pj+9iOOAUKLur8IIKjR/bi54GICUy0BHO6dzpWc0xqGK170F9NTv0bHe0qbh7jHgzq9MJrfcVD+XZAH17ho5tCGIo+z7CiC+rMWGTqmRopd/EQuzfx4Op4/85hoPlpKxdcxAfys0jpZ9tBMtROPsYKhCz01iDnHV2K95s4UwaQLbbx0VALVaXv1/4Yjw/PW4xK0syW/nqUtVqpfwPuX+fHf+bJ2s4kLnFBNwYAKFSU6znGmtJuq6aoxCunu2PbzI8xc7SYxHEfDqG8Zp29wtZcTJecWSDMBmywlaXjkXLzapvE7QIDAQAB
privateKey: MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDQotgTZO/irH927G7xC+rlk3nzISOP+7CzF+z3qmP72I44BQou6vwggqNH9uLngYgJTLQEc7p3OlZzTGoYrXvQX01O/Rsd7SpuHuMeDOr0wmt9xUP5dkAfXuGjm0IYij7PsKIL6sxYZOqZGil38RC7N/Hg6nj/zmGg+WkrF1zEB/KzSOln20Ey1E4+xgqELPTWIOcdXYr3mzhTBpAttvHRUAtVpe/X/hiPD89bjErSzJb+epS1Wql/A+5f58d/5snaziQucUE3BgAoVJTrOcaa0m6rpqjEK6e7Y9vMjzFztJjEcR8Oobxmnb3C1lxMl5xZIMwGbLCVpeORcvNqm8TtAgMBAAECggEBAKMhoQfRFYxMSkIHbluFcP5eyKylDbRoHOp726pvDUx/L/x3XFYBIHCfFOKRFSvk6SQ0WFFe176f27a9Wfu/sh7kVYNcflZw+YsvFXCKsy/70KZ/lr24izy8KHuPSyf6+E/WkW32Ah9fkNtzTFdfIzDv9m1hiIijq0x9l5C87KjNELnbvC0I6vwFOx0ak+JBbpaJ7IRjZxKZup7UIPvt9nbLzcbKelI83An2JUe8HNhrfWxH9UIyMOBoAY+bKCuAbUtHqSlImPiWyiCwE2/Fh7dmPSOAYYp9aZelnhd25jlR+eh4yaUoIID9ubmYVYbjcPW5SSNdfSZMfQ3oa79QeRUCgYEA6K4L+VLRiX8Dg7NCO1fM2+FTv2csTkPX6n7z/uu7kh0+wQDws+/C6Q906OtizvJBIJqFm2jPACNQCvnRixY1srgMJJlH/Rpeb4LtZGwdM1k0jAZIYQcBlGfaq3RaRI/+6+T0xdsh+7VF5A/smp/VXdK2xI3+JbLQ2wm9uN+3yZcCgYEA5Yvly7veDJYf2+8HIQkRhjWrWm1y5lCSe+HG+1ktfqnhN8YEOiPa71u0TXealL0T8EoKsqhWEjomxZ7n0jLigogz7OxxsGAE6HXAiKX0REINNYrq+1qNaqmkfLrhAJyg3JNgTSlb0xd56w7FSqOBttVL9INawGb1P98kYc5OzhsCgYBEfIY1urTGPcZxC2BhSzSXO7mEyv91ge6ZrQhwbj5lgYopEPfIXrgGFXCZ5j7NHu0ghZrx5WWYasxyjpmo0L65fgbE9wEDdLF7LRRmzJPDu2wGEwtW09MZNYBdmv++0ot8L4YEfr1/8xlBSZag5I7O8Oiu7gRyYDGtZy6are7QvQKBgQCaUZnUhOF7/rU+a4yUZf9VBeHD8k7LjaFdDWVzdvmB7P1PPJ185Lv8LN+jMORIWHD+GxjkEQ2ERXnpY7If+zuSW7Tk8/Reib7i9L7SXxc/iFRPCax9/NuTuKavgAdiHOp8P8v/M+3alS7OmuiCDDhZTT46DNDHBrCcFwzjgAo0vwKBgECBs6hEUVsYU74Uc64he8Zgkvj7wZ/yxnFlWmRRERprfBsuiY/y+DAf5ehezSRFpHXUrAkpeVXq2ydnr9BKTs6TV3AxlDMBNSndXsUYHENncR7tEHCSGRFTTu5jxdYA+k47R865Jh+2vQvPaPaXsEKSkDegvcFeUVR/yi5AsDub
#å¦æéæ©é对称å å¯ï¼åéè¦ä½¿ç¨è¯¥é
ç½®ï¼è¯¥é
ç½®ç±serviceAæä¾
serviceA:
rsa:
publicKey: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2BF9EZCscKNXYADtulIDNHaMnoxV5Yu91jpv+LiWabW2EO51b8Sx8+Ei59EebM4r+SMal0k4L2Z+cNagQSP4Wvpss82/MkGO8bnAFSxS2SOKw+a+c2PxByWUxvHo4pbyYGFVWAGDXLiI+IqiO/fEFfpy6rYQzMLDnfgMFngdS4AZmRyTdMKbQs8mWqBE5nC0PoU39o/lFowfgelEjHE9vhjtTha67KhYY3n+ueuxsYdRQ40Mg7aQ0+Kt/qKoSn9yRWyx09DheFAkYl4ZCQfd0sMotLQ4BZtk0YWMNHOc1w+fL1bOumaj7AaJi6nM/VvwylLJyia2GjJIDrdTfHiOnwIDAQAB
Açé ç½®
ymlå¤å¶ä»£ç serviceA:
rsa:
privateKey: MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDYEX0RkKxwo1dgAO26UgM0doyejFXli73WOm/4uJZptbYQ7nVvxLHz4SLn0R5sziv5IxqXSTgvZn5w1qBBI/ha+myzzb8yQY7xucAVLFLZI4rD5r5zY/EHJZTG8ejilvJgYVVYAYNcuIj4iqI798QV+nLqthDMwsOd+AwWeB1LgBmZHJN0wptCzyZaoETmcLQ+hTf2j+UWjB+B6USMcT2+GO1OFrrsqFhjef6567Gxh1FDjQyDtpDT4q3+oqhKf3JFbLHT0OF4UCRiXhkJB93Swyi0tDgFm2TRhYw0c5zXD58vVs66ZqPsBomLqcz9W/DKUsnKJrYaMkgOt1N8eI6fAgMBAAECggEAA5f23o3rcEwnLd+WFJ08lGjMWe63lwPF+oQqTJa1Wbi9+HYe2ecJlqbN79EYknKzZIdi79U17APmYnYPYEX64Xh8yljHr0xL1lVijneYQShILI3v6PdmkNndKZnoZ6xfB59WzgnoZ2hiTs/vdtPeHQd3VdQFX4J1wnDXsp/4zMKi1fDPt7rhqWrP5W6PXcoGGKIkN9zBlqrd1RBdnKXcwfFoHcFf2ikk6g3Kn50YMRe324eiHMm8z7W34Y3iSvZYHcKBMgsDklFerw1WOGHTN61oMr+8/NTtCsy1AnCH4PrwX/ryO17mh5xNzo/ZSZRRezR92/hmwUIuOO+3FWIE4QKBgQD05wYMVlGKn1fm+sn4hn+ErC6NifXj3MkNdjs8oSHzLrYr6ea6xIvbxesZvqzqz1Fh68bHjpJPOBKwgFnl7+dLXYLNmKjry1iK0o/MMZTtrGUwMEnWHRrpmxXH6B0cnBecZUReuJ9XfKZIfd9ksHHsUY7IGv1CHcblVP/IhrpnxwKBgQDh2/n0cAh1jygGevlXGK/rxuRSlbVgtxJWLAtY8Yolf2BklSiTwmqtp7nzNn8sxRvgfQCZaLqpjC/o/wtC3Ba5b4StJQejoXkCNhVmRdLbIQ2tUxwAElPjFhWf3C5/4B6uBeLyC9izp4wTSYbNbPKxcUGkkfpPbWdHsFZOG4gSaQKBgA/me/cLF6o3ZD6j478WBGt5vmAEKAnOSONt3LS4BXtDeiJpwkg4AJiZRgVa4uEv6qm/5B0KvacVDemVu8B5DfxPqvFsSvNcNXh16U4pnfC8c6loSTL0ms21+vkKsfEslT/bN1ArDnVgq28jdQCVkB/2v51wWycSxdoX5a+AR9P7AoGAMvTwZefI4M0VmLCyBKZ7OlS7Oq6wJ0vmhS6WuNB1/JPKaacFaqDYdKl82JSZCL7H1VQeiH4KbypDvOud3M3PCrNQWcga+x35MTiGh3aFZg8FCO/RR2rbJkbbRh/lFdC420ZUt4tYrt/ESK20DjDgaIxG5RxSPw1N2ey87A5mGtECgYEAlA12yuxBb6qmG3OUSlacSfcKnxZIC3L1IMqxlXL8eG3MB4dI6QYesc3odmaxmy9csgHs+pTyLfM3yB9Ocl572OW5WcEnod5o1EIup9hxB4IG/xSECYVFHlGKfIgbd/JhWtqloYZrwx+kVX/Iw02z18R32DRqBtK4MQ3klOYH86s=
B跳转A并å å¯ç¨æ·ä¿¡æ¯
javaå¤å¶ä»£ç /**
* com.itaq.cheetah.serviceB.controller.ToServiceAController#redirectToServiceA
* 跳转 ServiceA æå¡
*
* @return ServiceAè¿åçéå®åé¾æ¥
*/
@GetMapping
public WrapperResult<String> redirectToServiceA() {
//1ãæ建ç¨æ·ä¿¡æ¯
SsoUserInfo data = buildSsoUserInfo();
Long timestamp = System.currentTimeMillis();
String flowId = UUID.randomUUID().toString();
String businessId = "sso";
String dataEncrypt;
String encryptType = configProperties.getEncryptType();
//2ãæ ¹æ®é
ç½®éæ©åªç§æ¹å¼å å¯
switch (encryptType) {
case "AES":
AES aes = new AES(configProperties.getAppSecret().getBytes(StandardCharsets.UTF_8));
dataEncrypt = aes.encryptBase64(JsonUtils.toString(data), StandardCharsets.UTF_8);
break;
case "RSA":
RSA rsa = new RSA(AsymmetricAlgorithm.RSA_ECB_PKCS1.getValue(), null, configProperties.getServiceAPublicKey());
dataEncrypt = rsa.encryptBase64(JsonUtils.toString(data), StandardCharsets.UTF_8, KeyType.PublicKey);
break;
default:
return WrapperResult.faild("æªé
ç½®å å¯æ¹å¼");
}
//3ãå°ä»¥ä¸ä¿¡æ¯è¿è¡ç¾å
SsoSignSource build = SsoSignSource.builder()
.platformId(configProperties.getAppId())
.platformSecret(configProperties.getAppSecret())
.businessId(businessId)
.data(dataEncrypt)
.flowId(flowId)
.timestamp(timestamp)
.build();
String sign = build.sign();
log.info("sign source={}", JsonUtils.toPrettyString(build));
//4ãæ建请æ±ä½
ToServiceAReq req = ToServiceAReq.builder()
.platformId(configProperties.getAppId())
.businessId("sso")
.flowId(flowId)
.timestamp(timestamp)
.sign(sign)
.data(dataEncrypt)
.build();
//5ã跳转Açæä½
String s = HttpRequest.post("http://localhost:8081/serviceA")
.bodyString(JsonUtils.toString(req))
.execute()
.asString();
log.info("ç»æï¼{}", s);
return WrapperResult.success(s);
}
Aè·åç¨æ·ä¿¡æ¯åç»æä½
javaå¤å¶ä»£ç /**
* com.itaq.cheetah.serviceA.controller.ServiceAController#sso
*
* @return
*/
@PostMapping
public WrapperResult<SsoRespDto> sso(@VerifySign ToServiceAReq req) {
log.info("æ¶å°åç¹ç»å½ServiceAç请æ±ï¼{}", JsonUtils.toPrettyString(req));
//åæ¥ç¨æ·ä¿¡æ¯
//模æç»éçætoken
//è¿åæ¼æ¥çurlï¼token=xxx
//è¿åæ¼æ¥çurlï¼token=xxx
String url ="127.0.0.1:8081/index?token=xxx";
SsoRespDto ssoRespDto = new SsoRespDto();
ssoRespDto.setRedirectUrl(url);
return WrapperResult.success(ssoRespDto);
}
ä½ å¯è½ä¼å¥½å¥ï¼éªç¾è§£å¯çé»è¾å»åªäºï¼
æ¤å¤æ们éè¿æ³¨è§£çæ¹å¼å®ç°èªå¨éªç¾å解å¯çé»è¾ï¼è³äºå ·ä½çé»è¾ï¼å¤§å®¶å¯ä»¥åå¤âssoâè·åæºç èªè¡è§£è¯»ï¼å½ç¶åç»é¿Qè¿ä¼æ¨åºæ°çæç« è¿è¡è¯¦ç»ç讲解ï¼ç¹å»å ³æ³¨ãé¿Q说代ç ãè¿è¡é¢çº¦å§ï¼
æµè¯
è¡¥å ç¥è¯
æ¬æä¸ç¨å°ç RSA çå¯é¥æ¯éè¿å¨çº¿ç½ç«https://www.bchrt.com/tools/rsa/çæçï¼å½ç¶å¤§å®¶ä¹å¯ä»¥ä½¿ç¨ hutool ä¸ç RSA ç±»æ¥çæï¼ä¹å¯ä»¥ä½¿ç¨ java èªå¸¦ç security æ¥çæã
ä½è ï¼é¿Q说代ç
é¾æ¥ï¼https://juejin.cn/post/7239259798267920443