369 lines
17 KiB
Plaintext
369 lines
17 KiB
Plaintext
|
|
package com.securityControl.auth.igwUtils;
|
|||
|
|
|
|||
|
|
import com.aostarit.sgid.agent.EncryptHelper;
|
|||
|
|
import com.aostarit.smcrypto.Sm3Utils;
|
|||
|
|
import com.google.gson.JsonObject;
|
|||
|
|
import com.securityControl.auth.igwUtils.EnDecryptUtil;
|
|||
|
|
import com.securityControl.auth.igwUtils.InterfaceEnv;
|
|||
|
|
import com.securityControl.auth.igwUtils.SerUtil;
|
|||
|
|
import com.securityControl.auth.pojo.*;
|
|||
|
|
import org.apache.http.Header;
|
|||
|
|
import org.apache.http.HttpEntity;
|
|||
|
|
import org.apache.http.client.ResponseHandler;
|
|||
|
|
import org.apache.http.client.config.RequestConfig;
|
|||
|
|
import org.apache.http.client.entity.UrlEncodedFormEntity;
|
|||
|
|
import org.apache.http.client.methods.CloseableHttpResponse;
|
|||
|
|
import org.apache.http.client.methods.HttpPost;
|
|||
|
|
import org.apache.http.config.Registry;
|
|||
|
|
import org.apache.http.config.RegistryBuilder;
|
|||
|
|
import org.apache.http.conn.socket.ConnectionSocketFactory;
|
|||
|
|
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
|
|||
|
|
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
|
|||
|
|
import org.apache.http.conn.ssl.NoopHostnameVerifier;
|
|||
|
|
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
|
|||
|
|
import org.apache.http.conn.ssl.TrustStrategy;
|
|||
|
|
import org.apache.http.entity.StringEntity;
|
|||
|
|
import org.apache.http.impl.client.BasicResponseHandler;
|
|||
|
|
import org.apache.http.impl.client.CloseableHttpClient;
|
|||
|
|
import org.apache.http.impl.client.HttpClients;
|
|||
|
|
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
|||
|
|
import org.apache.http.message.BasicNameValuePair;
|
|||
|
|
import org.apache.http.ssl.SSLContexts;
|
|||
|
|
import org.apache.http.util.EntityUtils;
|
|||
|
|
|
|||
|
|
import javax.net.ssl.SSLContext;
|
|||
|
|
import java.io.IOException;
|
|||
|
|
import java.io.UnsupportedEncodingException;
|
|||
|
|
import java.nio.charset.StandardCharsets;
|
|||
|
|
import java.util.ArrayList;
|
|||
|
|
import java.util.HashMap;
|
|||
|
|
import java.util.LinkedHashMap;
|
|||
|
|
import java.util.List;
|
|||
|
|
import java.util.Map;
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 单点登录(新)-二级应用获取用户信息demo
|
|||
|
|
* <p>
|
|||
|
|
* {"code":"29547","message":"error","data":"Get ISC user code info by wechat code failure "}
|
|||
|
|
* 出现类似信息表示code已被消费,或者code错误,需要从i国网内重新获取
|
|||
|
|
*
|
|||
|
|
* @author shimengran
|
|||
|
|
*/
|
|||
|
|
public class IgwSingleSignOn {
|
|||
|
|
|
|||
|
|
private static CloseableHttpClient CLIENT;
|
|||
|
|
|
|||
|
|
static {
|
|||
|
|
//设置超时时间
|
|||
|
|
RequestConfig requestConfig = RequestConfig.custom()
|
|||
|
|
.setConnectTimeout(5000)
|
|||
|
|
.setConnectionRequestTimeout(30000)
|
|||
|
|
.setSocketTimeout(30000)
|
|||
|
|
.build();
|
|||
|
|
TrustStrategy acceptingTrustStrategy = (x509Certificates, authType) -> true;
|
|||
|
|
SSLContext sslContext;
|
|||
|
|
try {
|
|||
|
|
sslContext = SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build();
|
|||
|
|
} catch (Exception e) {
|
|||
|
|
throw new RuntimeException(e.getMessage(), e);
|
|||
|
|
}
|
|||
|
|
LayeredConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext, new NoopHostnameVerifier());
|
|||
|
|
Registry<ConnectionSocketFactory> sfr = RegistryBuilder.<ConnectionSocketFactory>create().register("http", PlainConnectionSocketFactory.getSocketFactory()).register("https", csf != null ? csf : SSLConnectionSocketFactory.getSocketFactory()).build();
|
|||
|
|
PoolingHttpClientConnectionManager pollingConnectionManager = new PoolingHttpClientConnectionManager(sfr);
|
|||
|
|
CLIENT = HttpClients.custom().setSSLSocketFactory(csf)
|
|||
|
|
.setConnectionManager(pollingConnectionManager)
|
|||
|
|
.setDefaultRequestConfig(requestConfig)
|
|||
|
|
.build();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private static ResponseHandler<String> RESPONSE_HANDLER = new BasicResponseHandler();
|
|||
|
|
// --> isc app id
|
|||
|
|
private static String ISC_APP_ID = "424ffb874241409c8a7d0350f103513f";
|
|||
|
|
// --> signKey
|
|||
|
|
private static String SM2_PRIVATE_KEY = "00D515EE353393AD2CE9BF0AD17A5CC76E90B335143CD3ABF578718DD13369DACD";
|
|||
|
|
// --> isc secret
|
|||
|
|
private static String SM4_KEY = "f1bc301b044244b495973e156f342fbd";
|
|||
|
|
|
|||
|
|
public static void main(String[] args) {
|
|||
|
|
// 企信换取的CODE,每个code只能被消费一次
|
|||
|
|
String code = "LlkvHmalObT6uYZYK-jHuw0Avsji0arWOpFkEKmbmpo";
|
|||
|
|
|
|||
|
|
// 以下两个获取流程取其中一个使用,网省非总部应用建议使用第二个流程
|
|||
|
|
|
|||
|
|
// [流程1] -> 一级应用以 企信换取的CODE 直接获取用户信息
|
|||
|
|
// ISCUser userInfo = getUserInfoByIgwCode(code, ISC_APP_ID, SM4_KEY, SM2_PRIVATE_KEY, InterfaceEnv.UAT);
|
|||
|
|
// System.out.println(SerUtil.toJson(userInfo));
|
|||
|
|
|
|||
|
|
// [流程2] -> 二级应用(省侧)获取用户信息流程
|
|||
|
|
// !!!注意isc用户id,如果之前用的二级应用的相关接口且使用了isc用户id或组织id相关字段,建议使用该接口替换。
|
|||
|
|
// UserInfo userInfo = provinceApplicationGetUserInfo(code, ISC_APP_ID, SM4_KEY, SM2_PRIVATE_KEY, InterfaceEnv.UAT);
|
|||
|
|
String accessToken = getAccessToken("ec94e81f643d47569b2710c07ded639d", "075de29b69dd4e77a1fba981de334f28", "00DC1179A380376AC9175E34F09B8833E8C5DF4968F9904364F2C6B45DCFC61B59", InterfaceEnv.PRODUCT);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private static ISCUser getUserInfoByIgwCode(String code, String iscAppId, String sm4Key, String sm2PrivateKey, InterfaceEnv env) {
|
|||
|
|
String reqUrl = env == InterfaceEnv.UAT ? "https://igw.isgcc.net:18443/proxy/getUserByIgwCode" : "https://id.sgcc.com.cn:10443/igwmobile/proxy/getUserByIgwCode";
|
|||
|
|
IgwCodeUserParams params = new IgwCodeUserParams();
|
|||
|
|
params.setCODE(code);
|
|||
|
|
params.setAppId(iscAppId);
|
|||
|
|
CommonResult commonResult = postRequestJson(reqUrl, params, CommonResult.class, null);
|
|||
|
|
System.out.println(SerUtil.toJson(commonResult));
|
|||
|
|
String data = commonResult.getData();
|
|||
|
|
if (data == null) {
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
try {
|
|||
|
|
String userInfo = EnDecryptUtil.transferDecrypt(data, sm4Key, sm2PrivateKey);
|
|||
|
|
System.out.println(userInfo);
|
|||
|
|
return SerUtil.fromJson(userInfo, ISCUser.class);
|
|||
|
|
} catch (Exception e) {
|
|||
|
|
throw new RuntimeException(e);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static UserInfo provinceApplicationGetUserInfo(String unionCode, String iscAppId, String sm4Key, String sm2PrivateKey, InterfaceEnv env) {
|
|||
|
|
try {
|
|||
|
|
// !!!建议在前端处理, (该接口为总部统一部署,省侧互联网大区服务器如果要访问需要开墙)
|
|||
|
|
// 根据wechatCode获取用户级联编码信息
|
|||
|
|
// String unionCode = getUnionCodeByWechatCode(code, env);
|
|||
|
|
|
|||
|
|
// !!!建议放在后端处理(互联网大区可直接访问)
|
|||
|
|
// 获取密钥信息,uat环境和浙江生产环境获取token的方式有所区别,此步骤需要环境区分
|
|||
|
|
String accessToken = "";
|
|||
|
|
if (env == InterfaceEnv.UAT) {
|
|||
|
|
accessToken = getAccessToken(iscAppId, sm4Key, sm2PrivateKey, env);
|
|||
|
|
}
|
|||
|
|
// !!!建议放在后端处理(互联网大区可直接访问)
|
|||
|
|
// 根据级联编码获取用户信息
|
|||
|
|
UserInfo userInfo = getUserInfoByUnionCode(unionCode, iscAppId, sm2PrivateKey, accessToken, env);
|
|||
|
|
System.out.println(SerUtil.toJson(userInfo));
|
|||
|
|
return userInfo;
|
|||
|
|
} catch (Exception e) {
|
|||
|
|
// throw new RuntimeException(e.getMessage(), e);
|
|||
|
|
throw new RuntimeException("用户获取失败", e);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 根据i国网Code获取用户级联编码信息
|
|||
|
|
*
|
|||
|
|
* @param code i国网Code 该参数从i国网浏览器跳转获取
|
|||
|
|
* @param env
|
|||
|
|
* @return 级联编码
|
|||
|
|
* @throws Exception
|
|||
|
|
*/
|
|||
|
|
private static String getUnionCodeByWechatCode(String code, InterfaceEnv env) throws Exception {
|
|||
|
|
String reqUrl = env == InterfaceEnv.UAT ? "https://igw.isgcc.net:18443/proxy/getUserCodeByWechatCode" : "https://id.sgcc.com.cn:10443/igwmobile/proxy/getUserCodeByWechatCode";
|
|||
|
|
GetUnionCodeParams params = new GetUnionCodeParams();
|
|||
|
|
params.setCODE(code);
|
|||
|
|
params.setAppId(ISC_APP_ID);
|
|||
|
|
CommonResult commonResult = postRequestJson(reqUrl, params, CommonResult.class, null);
|
|||
|
|
String data = commonResult.getData();
|
|||
|
|
String res = EnDecryptUtil.transferDecrypt(data, SM4_KEY, SM2_PRIVATE_KEY);
|
|||
|
|
UnionUserCodeRes unionUserCodeRes = SerUtil.fromJson(res, UnionUserCodeRes.class);
|
|||
|
|
return unionUserCodeRes.getCode();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* uat环境获取accessToken
|
|||
|
|
*
|
|||
|
|
* @param appId appid
|
|||
|
|
* @param clientSecret clientSecret isc secret
|
|||
|
|
* @param env 环境参数,用于区分接口差异
|
|||
|
|
* @return accessToken
|
|||
|
|
*/
|
|||
|
|
private static String getAccessToken(String appId, String clientSecret, String sm2PrivateKey, InterfaceEnv env) {
|
|||
|
|
String url = env == InterfaceEnv.UAT ? "https://igw.isgcc.net:18443/zuul/sgid-provider-console/res/iscMincroService/getAccessToken" : "http://tyqxfrontmv.zj.sgcc.com.cn/isc_frontmv_serv/ticket/getAccessToken";
|
|||
|
|
Map<String, String> data = new HashMap<>(16);
|
|||
|
|
data.put("appId", appId);
|
|||
|
|
data.put("clientSecret", clientSecret);
|
|||
|
|
|
|||
|
|
// 第二步:创建httpPost对象
|
|||
|
|
HttpPost httpPost = new HttpPost(url);
|
|||
|
|
httpPost.setHeader("Accept", "*/*");
|
|||
|
|
String digest;
|
|||
|
|
try {
|
|||
|
|
if (env == InterfaceEnv.UAT) {
|
|||
|
|
digest = Sm3Utils.encryptFromText(SerUtil.toJson(data));
|
|||
|
|
} else {
|
|||
|
|
digest = EncryptHelper.sign(sm2PrivateKey, SerUtil.toJson(data));
|
|||
|
|
}
|
|||
|
|
} catch (Exception e) {
|
|||
|
|
throw new RuntimeException(e.getMessage(), e);
|
|||
|
|
}
|
|||
|
|
httpPost.setHeader("X-Acloud-Data-Sign", digest);
|
|||
|
|
httpPost.setHeader("X-Clientid", appId);
|
|||
|
|
for (Header allHeader : httpPost.getAllHeaders()) {
|
|||
|
|
System.out.println(allHeader.getName() + " : " + allHeader.getValue());
|
|||
|
|
}
|
|||
|
|
// 第三步:给httpPost设置JSON格式的参数
|
|||
|
|
// 环境区分
|
|||
|
|
if (env == InterfaceEnv.UAT) {
|
|||
|
|
httpPost.setHeader("Content-Type", "application/json;charset=UTF-8");
|
|||
|
|
StringEntity requestEntity = new StringEntity(SerUtil.toJson(data), "UTF-8");
|
|||
|
|
requestEntity.setContentEncoding("UTF-8");
|
|||
|
|
httpPost.setEntity(requestEntity);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (env == InterfaceEnv.PRODUCT) {
|
|||
|
|
httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded");
|
|||
|
|
List<BasicNameValuePair> form = new ArrayList<>();
|
|||
|
|
for (String name : data.keySet()) {
|
|||
|
|
form.add(new BasicNameValuePair(name, data.get(name)));
|
|||
|
|
}
|
|||
|
|
UrlEncodedFormEntity entity;
|
|||
|
|
try {
|
|||
|
|
entity = new UrlEncodedFormEntity(form, "utf-8");
|
|||
|
|
for (BasicNameValuePair basicNameValuePair : form) {
|
|||
|
|
System.out.println(basicNameValuePair.getName() + " : " + basicNameValuePair.getValue());
|
|||
|
|
}
|
|||
|
|
} catch (UnsupportedEncodingException e) {
|
|||
|
|
throw new RuntimeException(e.getMessage(), e);
|
|||
|
|
}
|
|||
|
|
httpPost.setEntity(entity);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
// 第四步:发送HttpPost请求,获取返回值
|
|||
|
|
// 调接口获取返回值时,必须用此方法
|
|||
|
|
try {
|
|||
|
|
String response = CLIENT.execute(httpPost, RESPONSE_HANDLER);
|
|||
|
|
System.out.println(response);
|
|||
|
|
JsonObject resObj = SerUtil.fromJson(response, JsonObject.class);
|
|||
|
|
if (env == InterfaceEnv.UAT) {
|
|||
|
|
return resObj.getAsJsonObject("data").get("accessToken").getAsString();
|
|||
|
|
} else {
|
|||
|
|
return resObj.get("data").getAsString();
|
|||
|
|
}
|
|||
|
|
} catch (IOException e) {
|
|||
|
|
throw new RuntimeException(e.getMessage(), e);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 根据级联编码获取用户信息
|
|||
|
|
*
|
|||
|
|
* @param unionCode 级联编码
|
|||
|
|
* @param iscAppId 用户appId
|
|||
|
|
* @param signKey sm2private 解密私钥
|
|||
|
|
* @param accessToken 口令
|
|||
|
|
* @return 用户信息
|
|||
|
|
*/
|
|||
|
|
private static UserInfo getUserInfoByUnionCode(String unionCode, String iscAppId, String signKey, String accessToken, InterfaceEnv env) {
|
|||
|
|
GetUserInfoParams getUserInfoParams = new GetUserInfoParams();
|
|||
|
|
getUserInfoParams.setCode(unionCode);
|
|||
|
|
|
|||
|
|
// header里的参数在生产环境不存在
|
|||
|
|
Map<String, String> headers = new HashMap<>(16);
|
|||
|
|
headers.put("X-Clientid", iscAppId);//注册系统时的appId
|
|||
|
|
if (env == InterfaceEnv.UAT) {
|
|||
|
|
try {
|
|||
|
|
headers.put("X-ISC-AccessToken", "Client " + accessToken);
|
|||
|
|
headers.put("X-Acloud-Data-Sign", EncryptHelper.sign(signKey, SerUtil.toJson(getUserInfoParams))); //请求json串的签名串
|
|||
|
|
} catch (Exception e) {
|
|||
|
|
throw new RuntimeException(e.getMessage(), e);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
headers.put("Accept", "*/*");
|
|||
|
|
// FIXME: isc接口未给出
|
|||
|
|
String reqUrl = env == InterfaceEnv.UAT ? "https://igw.isgcc.net:18443/sgid-provider-province-identity/identity/getUsersByCode" : "http://tyqxfrontmv.zj.sgcc.com.cn/sgid-provider-province-identity/identity/getUsersByCode";
|
|||
|
|
JsonObject userJsonObj = postRequestJson(reqUrl, getUserInfoParams, JsonObject.class, headers);
|
|||
|
|
JsonObject enUserInfo = userJsonObj.get("data").getAsJsonObject();
|
|||
|
|
try {
|
|||
|
|
return SerUtil.fromJson(SerUtil.toJson(enUserInfo), UserInfo.class);
|
|||
|
|
} catch (Exception e) {
|
|||
|
|
throw new RuntimeException(e.getMessage(), e);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private static <T> T postRequestJson(String url, Object obj, Class<T> resClz, Map<String, String> headers) {
|
|||
|
|
System.out.println("request url : " + url);
|
|||
|
|
System.out.println("request data : " + SerUtil.toJson(obj));
|
|||
|
|
System.out.println("request headers : " + SerUtil.toJson(headers));
|
|||
|
|
String jsonBody = SerUtil.toJson(obj);
|
|||
|
|
StringEntity requestEntity;
|
|||
|
|
try {
|
|||
|
|
requestEntity = new StringEntity(jsonBody, StandardCharsets.UTF_8);
|
|||
|
|
} catch (Exception e) {
|
|||
|
|
e.printStackTrace();
|
|||
|
|
throw e;
|
|||
|
|
}
|
|||
|
|
requestEntity.setContentType("application/json");
|
|||
|
|
|
|||
|
|
HttpPost httpPost = new HttpPost(url);
|
|||
|
|
httpPost.setEntity(requestEntity);
|
|||
|
|
httpPost.setHeader("Content-Type", "application/json;charset=utf8");
|
|||
|
|
if (headers != null && !headers.isEmpty()) {
|
|||
|
|
headers.forEach(httpPost::setHeader);
|
|||
|
|
}
|
|||
|
|
CloseableHttpResponse response;
|
|||
|
|
try {
|
|||
|
|
response = CLIENT.execute(httpPost);
|
|||
|
|
} catch (IOException e) {
|
|||
|
|
throw new RuntimeException(e.getMessage(), e);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
System.out.println("response status : " + response.getStatusLine().getStatusCode());
|
|||
|
|
HttpEntity responseEntity = response.getEntity();
|
|||
|
|
String result;
|
|||
|
|
try {
|
|||
|
|
result = EntityUtils.toString(responseEntity);
|
|||
|
|
System.out.println("response data : " + result);
|
|||
|
|
} catch (IOException e) {
|
|||
|
|
throw new RuntimeException(e.getMessage(), e);
|
|||
|
|
}
|
|||
|
|
return SerUtil.fromJson(result, resClz);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
public static String getAccessToken2(String url, String appId, String secret, String signKey) throws Exception {
|
|||
|
|
String returnValue = "这是默认返回值,接口调用失败";
|
|||
|
|
String encode = "utf-8";
|
|||
|
|
Map<String, String> params = new LinkedHashMap<String, String>();
|
|||
|
|
CloseableHttpClient httpClient = HttpClients.createDefault();
|
|||
|
|
ResponseHandler<String> responseHandler = new BasicResponseHandler();
|
|||
|
|
try {
|
|||
|
|
//准备请求参数,LinkedHashMap保持参数有序
|
|||
|
|
params.put("appId", appId);
|
|||
|
|
params.put("clientSecret", secret);
|
|||
|
|
// 第一步:创建HttpClient对象
|
|||
|
|
httpClient = HttpClients.createDefault();
|
|||
|
|
// 第二步:创建httpPost对象
|
|||
|
|
HttpPost httpPost = new HttpPost(url);
|
|||
|
|
System.out.println("执行>" + url);
|
|||
|
|
//对请求参数json串签名,注意json串不能被格式化美化处理,如换行等,不能处理后掉了原有的属性
|
|||
|
|
String sig = EncryptHelper.sign(signKey, SerUtil.toJson(params));
|
|||
|
|
System.out.println("参数:" + params.toString());
|
|||
|
|
// 设置头信息
|
|||
|
|
httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded");//必须是 application/x-www-form-urlencoded
|
|||
|
|
httpPost.setHeader("X-Clientid", appId);//注册系统时的appId
|
|||
|
|
httpPost.setHeader("X-Acloud-Data-Sign", sig);//请求json串的签名串
|
|||
|
|
httpPost.setHeader("Accept", "*/*");
|
|||
|
|
|
|||
|
|
// 第三步:给httpPost设置的参数
|
|||
|
|
List<BasicNameValuePair> form = new ArrayList<BasicNameValuePair>();
|
|||
|
|
for (String name : params.keySet()) {
|
|||
|
|
form.add(new BasicNameValuePair(name, params.get(name)));
|
|||
|
|
}
|
|||
|
|
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(form, encode);
|
|||
|
|
httpPost.setEntity(entity);
|
|||
|
|
|
|||
|
|
// 第四步:发送HttpPost请求,获取返回值
|
|||
|
|
returnValue = httpClient.execute(httpPost, responseHandler); // 调接口获取返回值时,必须用此方法
|
|||
|
|
// 打出返回值
|
|||
|
|
System.out.println("返回值>" + returnValue + "\n");
|
|||
|
|
//fastjson处理数据
|
|||
|
|
return "";
|
|||
|
|
} catch (Exception e) {
|
|||
|
|
e.printStackTrace();
|
|||
|
|
} finally {
|
|||
|
|
try {
|
|||
|
|
httpClient.close();
|
|||
|
|
} catch (IOException e) {
|
|||
|
|
e.printStackTrace();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return "";
|
|||
|
|
}
|
|||
|
|
}
|