主要针对pc端的用户体系对接
第一、需要确认需要使用什么方式进行接入,一共提供了两种网络环境
1.政务外网,2.公网
其中政务外网环境需要服务器支持,对接前最好询问一下是否有连接支持
第二、接入用户体系目前分为法人登录(企业登录)与个人登录,这两个用户体系的对接分别对应着两家公司(易和与天谷)
第三、对接的两家公司的逻辑有些许不同但大体是一致的,废话不多直接讲
对接需要业主方去浙江省一体化数字资源系统(公共应用组件服务超市)去申请
申请(需要材料)
通过后会得到对接文档或者材料(一般来说是政务外网的)
SecretKey和AccessKey以及对接公司的联系方式,之后去联系一下说明来意之后不会去创建钉钉群进行交流之后就可以开展对接
个人登录:
前端
https://puser.zjzwfw.gov.cn/sso/usp.do?action=ssoLogin&servicecode=【接入代码】&goto=XXXX
后端
政务外网
https://interface.zjzwfw.gov.cn/gateway/component/routing/agent.htm
公网
https://appapi.zjzwfw.gov.cn/sso/servlet/simpleauth
法人登录:
前端
https://esso.zjzwfw.gov.cn/opensso/spsaehandler/metaAlias/sp?spappurl=回调地址?goto=xxxx
后端
政务外网
https://interface.zjzwfw.gov.cn/gateway/component/routing/agent.htm
公网
https://ssoapi.zjzwfw.gov.cn/rest/user/query
法人登录需要给与对接的公司一个回调地址让其配置,用来接收票据与令牌(回调地址必须为post
(ps:如果是通过政务外网的接口回调地址的那台服务器是必须能连接政务外网的)
https://esso.zjzwfw.gov.cn/opensso/spsaehandler/metaAlias/sp?spappurl=回调地址?goto=xxxx
spappurl:即是回调地址(后端)
goto:为之后跳转的地址一般指前端
回调地址代码
@PostMapping("/getSSOToken")
public void getSSOToken(HttpServletRequest request, HttpServletResponse response) {
response.setCharacterEncoding("UTF-8");
// 跳转Url
String redirectUrl = "";
// ssoticket是跨session用的,在原先链接里面加上&ssoticket=就可以实现跨session登录
log.info("--------------------------ssoticket {}--------------------------", request.getParameter("ssoticket"));
// 从Request请求的参数中获取ssotoken
String ssotoken = request.getParameter("ssotoken");
log.info("--------------------------ssotoken:{}--------------------------", ssotoken);
// legalPersonService.getLegalPersonInfo(ssotoken);
// 取具体办事事项地址(若此项有值,成功登录后请跳转此地址到具体事项,否则跳转系统首页)
String gotoUrl = request.getQueryString();
if (null != gotoUrl && !"".equals(gotoUrl.trim())) {
// 清理事项地址前的“goto=”标识
gotoUrl = gotoUrl.substring(5);
log.info("--------------------------具体业务办理地址 {}--------------------------", gotoUrl);
}
response.setHeader("refresh", "0;URL=" + gotoUrl);
}
政务外网其实调用封装了的公网的接口,通过上面的回调地址我们就可以获取到 ssotoken通过ssotoken获取用户信息
public JSONObject getLegalPersonInfoOuter(String token) {
long l = System.currentTimeMillis();
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.add("Content-Type", "application/json;charset=UTF-8");
requestHeaders.add("zjgxfwxt-interface-code", "atg.biz.userquery");//方法名称
requestHeaders.add("zjgxfwxt-access-key", legalPersonConfig.getAppAccess());//ak
requestHeaders.add("zjgxfwxt-sign", Md5Utils.md5(legalPersonConfig.getAppAccess() + legalPersonConfig.getAppSecret() + l));//ak+sk+时间戳
requestHeaders.add("zjgxfwxt-time", String.valueOf(l));
HashMap<String, String> stringStringHashMap = new HashMap<>(16);
stringStringHashMap.put("token", token);
HttpEntity<HashMap<String, String>> httpEntity = new HttpEntity<>(stringStringHashMap, requestHeaders);
RestTemplate restTemplate = new RestTemplate();
Map map = restTemplate.postForObject(legalPersonConfig.getInterfaceUrl(), httpEntity, Map.class);
JSONObject jsonObject = new JSONObject();
log.info("外网 政务网企业{}", map);
assert map != null;
if ("0".equals(map.get("code").toString())) {
JSONObject data = JSONUtil.parseObj(map.get("data"));
if ("0".equals(data.getStr("errCode"))) {
jsonObject = data.getJSONObject("info");
}
} else {
log.error("获取企业信息失败:{}", map);
}
return jsonObject;
}
公网与政务外网的ak和sk是不兼容的需要去额外申请(联系对接人员)
projectId与projectSecret
@SneakyThrows
public JSONObject getLegalPersonInfoPublic(String token) {
HashMap<String, String> stringStringHashMap = new HashMap<>(16);
stringStringHashMap.put("token", token);
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.add("Content-Type", "application/json");
requestHeaders.add("Charset", "UTF-8");
requestHeaders.add("x-esso-project-id", legalPersonConfig.getProjectId());
requestHeaders.add("x-esso-signature", HmacSHA256(JSONUtil.toJsonStr(stringStringHashMap), legalPersonConfig.getProjectSecret()));
HttpEntity<HashMap<String, String>> httpEntity = new HttpEntity<>(stringStringHashMap, requestHeaders);
RestTemplate restTemplate = new RestTemplate();
String str = restTemplate.postForObject(legalPersonConfig.getInterfaceUrlPublic(), httpEntity, String.class);
JSONObject jsonObject = new JSONObject();
JSONObject map = JSONUtil.parseObj(str);
log.info("公网政务网企业{}", map);
if ("0".equals(map.getStr("errCode"))) {
jsonObject = JSONUtil.parseObj(map.get("info"));
}
return jsonObject;
}
法人登录需要给与对接的公司一个回调地址让其配置,用来接收票据
(ps:如果是通过政务外网的接口回调地址的那台服务器是必须能连接政务外网的)
https://puser.zjzwfw.gov.cn/sso/usp.do?action=ssoLogin&servicecode=【接入代码】&goto=XXXX
servicecode:即是ak
goto:为之后跳转的地址一般指前端
servicepwd:既是sk
回调地址代码
@RequestMapping ("/getAuthentication/ticket")
public void getAuthentication(HttpServletRequest request, HttpServletResponse response) {
response.setCharacterEncoding("UTF-8");
String ticket = request.getParameter("ticket");
// 取具体办事事项地址(若此项有值,成功登录后请跳转此地址到具体事项,否则跳转系统首页)
String gotoUrl = request.getParameter("sp");
URI uri = null;
if (null != gotoUrl && !"".equals(gotoUrl.trim())) {
log.info("--------------------------具体业务办理地址 {}--------------------------", gotoUrl);
}
response.setHeader("refresh", "0;URL=" + gotoUrl);
}
同理调用封装了的公网的接口,通过上面的回调地址我们就可以获取到 ticket通过ticket获取用户信息
其中只需要调用票据认证接口获取token之后通过token调用根据令牌获取用户详细信息接口即可
ps:注意点其中头部的时间戳是正常的时间戳,作为参数的时间戳是特殊格式的时间,而且参数走的是queryParam形式不是body
@Override
public JSONObject getTokenByTicket(String ticket) {
HashMap<String, String> stringStringHashMap = new HashMap<>(16);
stringStringHashMap.put("method", "ticketValidation");
stringStringHashMap.put("st", ticket);
JSONObject jsonObject;
//判断是走公网还是外网
if ("1".equals(personageConfig.getOuterOrPublic())) {
jsonObject = sendPostPublic(stringStringHashMap);
} else {
jsonObject = sendPostOuter(personageConfig.getPaperCertification(), stringStringHashMap);
}
log.info("票据信息获取{}", jsonObject);
return jsonObject;
}
@Override
public JSONObject getTokenByUser(String token) {
HashMap<String, String> stringStringHashMap = new HashMap<>(16);
stringStringHashMap.put("method", "getUserInfo");
stringStringHashMap.put("token", token);
JSONObject jsonObject;
if ("1".equals(personageConfig.getOuterOrPublic())) {
jsonObject = sendPostPublic(stringStringHashMap);
} else {
jsonObject = sendPostOuter(personageConfig.getUserInfo(), stringStringHashMap);
}
log.info("用户信息获取{}", jsonObject);
return jsonObject;
}
//interfaceCode为外网特有既interface-code
public JSONObject sendPostOuter(String interfaceCode, HashMap<String, String> hashMap) {
Date date = new Date();
DateFormat sdf3 = new SimpleDateFormat("yyyyMMddHHmmss");
String time = sdf3.format(date);
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.add("Content-Type", "application/json;charset=UTF-8");
requestHeaders.add("zjgxfwxt-interface-code", interfaceCode);
requestHeaders.add("zjgxfwxt-access-key", personageConfig.getAppAccess());
requestHeaders.add("zjgxfwxt-sign", Md5Utils.md5(personageConfig.getAppAccess() + personageConfig.getAppSecret() + date.getTime()));
requestHeaders.add("zjgxfwxt-time", time);
hashMap.put("servicecode", personageConfig.getAppAccess());
hashMap.put("time", time);
hashMap.put("sign", Md5Utils.md5(personageConfig.getAppAccess() + personageConfig.getAppSecret() + time));
hashMap.put("datatype", "json");
UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUriString(personageConfig.getInterfaceUrl());
hashMap.forEach(uriComponentsBuilder::queryParam);
UriComponents uriComponents = uriComponentsBuilder.build();
URI uri = uriComponents.toUri();
HttpEntity<HashMap<String, String>> httpEntity = new HttpEntity<>(hashMap, requestHeaders);
RestTemplate restTemplate = new RestTemplate();
String str = restTemplate.postForObject(uri, httpEntity, String.class);
log.info("外网请求结果:{}" , str);
JSONObject jsonObject = new JSONObject();
Map map = JSONUtil.toBean(JSONUtil.parseObj(str), Map.class);
assert map != null;
if ("0".equals(map.get("code").toString())) {
JSONObject data = JSONUtil.parseObj(map.get("data"));
if ("0".equals(data.getStr("result"))) {
jsonObject = data;
}
}
return jsonObject;
}
上方代码已经有了只放调用方式
public JSONObject sendPostPublic(HashMap<String, String> hashMap) {
Date date = new Date();
DateFormat sdf3 = new SimpleDateFormat("yyyyMMddHHmmss");
String time = sdf3.format(date);
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.add("Content-Type", "application/json;charset=UTF-8");
hashMap.put("servicecode", personageConfig.getAppAccessPublic());
hashMap.put("time", time);
hashMap.put("sign", Md5Utils.md5(personageConfig.getAppAccessPublic() + personageConfig.getAppSecretPublic() + time));
hashMap.put("datatype", "json");
UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUriString(personageConfig.getInterfaceUrlPublic());
hashMap.forEach(uriComponentsBuilder::queryParam);
UriComponents uriComponents = uriComponentsBuilder.build();
URI uri = uriComponents.toUri();
HttpEntity<HashMap<String, String>> httpEntity = new HttpEntity<>(hashMap, requestHeaders);
RestTemplate restTemplate = new RestTemplate();
String str = restTemplate.postForObject(uri, httpEntity, String.class);
log.info("公网请求结果:{}",str);
JSONObject jsonObject = new JSONObject();
JSONObject map = JSONUtil.parseObj(str);
if ("0".equals(map.getStr("result"))) {
jsonObject = map;
}
return jsonObject;
}
md5加密
import lombok.SneakyThrows;
import java.security.MessageDigest;
public class Md5Utils {
/**
* Md 5 string.
*
* @param src the src
* @param charset the charset
* @return the string
*/
@SneakyThrows
private static String md5(final String src, final String charset) {
MessageDigest md5;
StringBuilder hexValue = new StringBuilder(32);
md5 = MessageDigest.getInstance("MD5");
byte[] byteArray;
byteArray = src.getBytes(charset);
byte[] md5Bytes = md5.digest(byteArray);
for (byte md5Byte : md5Bytes) {
int val = ((int) md5Byte) & 0xff;
if (val < 16) {
hexValue.append("0");
}
hexValue.append(Integer.toHexString(val));
}
return hexValue.toString();
}
/**
* Md 5 string.
*
* @param src the src
* @return the string
*/
public static String md5(final String src) {
return md5(src, "UTF-8");
}
}
HmacSHA256加密
public String HmacSHA256(String data, String key) throws Exception {
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
sha256_HMAC.init(secret_key);
byte[] array = sha256_HMAC.doFinal(data.getBytes(StandardCharsets.UTF_8));
StringBuilder sb = new StringBuilder();
for (byte item : array) {
sb.append(Integer.toHexString((item & 0xFF) | 0x100), 1, 3);
}
return sb.toString();
}
我想各位拿到了用户信息就知道怎么搞了对吗,baby