Commit 2c397c16 by zhu.zewen

新增云签相关接口

parent 603864e2
Showing with 1315 additions and 61 deletions
......@@ -59,10 +59,47 @@ mysql-bak:
username: jmai
password: IhxDs1fPoIkEpdLZ
# ################################################
# 云签配置
# ################################################
# 仅测试用
cloudsign:
businessOrgCode: 455835303
businessSystemCode: 1176
businessSystemAppID: w6qpjDk1WBSrFCfgcj
# 云签名服务基础地址
# 内网
# host: http://192.168.2.194:18087
# 公网测试
host: http://www.jztech.top:18087
# 是否开启测试:true - 开启,false - 关闭(默认)
testEnabled: true
# 生产
businessOrgCode: xxx
businessSystemCode: xxx
businessSystemAppID: xxx
# 测试
testBusinessOrgCode: 455835303
testBusinessSystemCode: 1176
testBusinessSystemAppID: w6qpjDk1WBSrFCfgcj
# API
# PIN码登录接口
pinloginUrl: /v1.0/cloudsign/loginbypin
# 生成登录二维码接口
genloginqrcodeUrl: /v1.0/cloudsign/genloginqrcode
# 二维码登录接口
qrcodeloginUrl: /v1.0/cloudsign/genloginqrcode
# 签名数据接口
signdataUrl: /v1.0/cloudsign/signdata
# 获取印章接口
getstampUrl: /v1.0/cloudsign/getstamp
# 查询用户令牌状态接口
querystatusUrl: /v1.0/cloudsign/usertoken/queryStatus
# 获取登录结果接口
getloginresultUrl: /v1.0/cloudsign/getLoginResult/web
# 获取证书信息接口
getcertinfoUrl: /v1.0/cloudsign/getcertinfo
# 验证数据接口
verifydataUrl: /v1.0/cloudsign/verify/data
# ################################################
# 交接单配置
......
package com.jmai.physic.cloudsign;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "CloudSignCallbackRequest", description = "云签系统回调请求参数")
public class CloudSignCallbackRequest {
@ApiModelProperty(value = "此次登录任务的唯一标识,通301返回值", required = true)
private String claimUuid;
@ApiModelProperty(value = "登录状态:0表示登录成功,1表示登录失败,2表示取消登录", required = true)
private String loginStatus;
@ApiModelProperty(value = "云签账号", required = true)
private String relBizNo;
@ApiModelProperty(value = "加密令牌,用于登录后的CA签名等操作使用")
private String encryptedToken;
}
\ No newline at end of file
package com.jmai.physic.cloudsign;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "CloudSignCallbackResponse", description = "云签系统回调响应参数")
public class CloudSignCallbackResponse {
@ApiModelProperty(value = "状态码,非0表示执行失败")
private Integer statusCode;
@ApiModelProperty(value = "状态信息")
private String eventMsg;
}
\ No newline at end of file
......@@ -17,86 +17,104 @@ import javax.annotation.Resource;
public class CloudsignService {
private static final String HOST = "http://192.168.2.194:18087";
private static final String loginbypin = HOST+"/v1.0/cloudsign/loginbypin";
private static final String genloginqrcode =HOST+"/v1.0/cloudsign/genloginqrcode";
private static final String signdata =HOST+"/v1.0/cloudsign/signdata";
private static final String getstamp =HOST+"/v1.0/cloudsign/getstamp";
@Resource
private CloudSignProperties cloudSignProperties;
private String buildUrl(String endpoint) {
return cloudSignProperties.getHost() + endpoint;
}
/**
* PIN吗登录
* 生成登录二维码
* @param request
*/
public GenloginqrcodeRespon loginbypin(LoginBypinRequest request){
public GenloginqrcodeRespon genLoginQrCode(GenloginqrcodeRequest request){
String logTip = "genLoginQrCode";
String json = OpenUtil.toJson(request);
try {
log.info("{}-入参: {}", logTip, json);
String response = HttpUtils.sendPostRequestAndParse(buildUrl(cloudSignProperties.getGenloginqrcodeUrl()), json, null);
log.info("{}-返回数据: {}", logTip, response);
if(ObjectUtil.isEmpty(response)){
throw new ServiceException("获取失败");
}
GenloginqrcodeRespon genloginqrcodeRespon = JSON.parseObject(response, GenloginqrcodeRespon.class);
return genloginqrcodeRespon;
} catch (Exception e) {
log.error("获取二维码失败:" + e.getMessage(), e);
throw new ServiceException("genLoginQrCode-获取二维码失败", e);
}
}
request.setBusinessOrgCode(cloudSignProperties.getBusinessOrgCode());
request.setBusinessSystemCode(cloudSignProperties.getBusinessSystemCode());
request.setBusinessSystemAppID(cloudSignProperties.getBusinessSystemApplD());
request.setLoginType(1);
String logTip = "loginbypin";
/**
* PIN码登录
*/
public GenloginqrcodeRespon pinLogin(PinLoginRequest request){
request.setLoginType(1);
String logTip = "pinLogin";
String json = OpenUtil.toJson(request);
try {
log.info("{}-入参:{}",logTip,json);
String response = HttpUtils.sendPostRequestAndParse(loginbypin, json, null);
log.info("{}-返回数据:{}",logTip,response);
String response = HttpUtils.sendPostRequestAndParse(buildUrl(cloudSignProperties.getPinloginUrl()), json, null);
log.info("{}-返回数据: {}",logTip,response);
if(ObjectUtil.isEmpty(response)){
throw new ServiceException("获取失败");
}
GenloginqrcodeRespon genloginqrcodeRespon = JSON.parseObject(response, GenloginqrcodeRespon.class);
return genloginqrcodeRespon;
} catch (Exception exception) {
log.error("获取令牌失败,e:{}"+exception.getMessage());
throw new ServiceException("获取失败");
} catch (Exception e) {
log.error("获取令牌失败:"+e.getMessage(), e);
throw new ServiceException("pinLogin-获取令牌失败", e);
}
}
/**
* 请求云签二维码
* 二维码登录
* @param request
*/
public void genloginqrcode(GenloginqrcodeRequest request){
String logTip = "genloginqrcode";
public QRCodeLoginResponse qrCodeLogin(QRCodeLoginRequest request){
String logTip = "qrCodeLogin";
String json = OpenUtil.toJson(request);
try {
log.info("{}-入参:{}",logTip,json);
String response = HttpUtils.sendPostRequestAndParse(genloginqrcode, json, null);
log.info("{}-返回数据:{}",logTip,response);
log.info("{}-入参: {}", logTip, json);
String response = HttpUtils.sendPostRequestAndParse(buildUrl(cloudSignProperties.getQrcodeloginUrl()), json, null);
log.info("{}-返回数据: {}", logTip, response);
if(ObjectUtil.isEmpty(response)){
throw new ServiceException("获取失败");
}
GenloginqrcodeRespon genloginqrcodeRespon = JSON.parseObject(response, GenloginqrcodeRespon.class);
QRCodeLoginResponse qrCodeLoginResponse = JSON.parseObject(response, QRCodeLoginResponse.class);
return qrCodeLoginResponse;
} catch (Exception exception) {
log.error("获取二维码失败,e:{}", exception.getMessage());
throw new ServiceException("获取失败");
}
}
public String sign(String encryptedToken,String relBizNo,String base64SourceData){
// SignDataRequest request = new SignDataRequest();
// request.setBusinessOrgCode(cloudSignProperties.getBusinessOrgCode());
// request.setBusinessSystemCode(cloudSignProperties.getBusinessSystemCode());
// request.setBusinessSystemAppID(cloudSignProperties.getBusinessSystemApplD());
// request.setBusinessTypeCode("007");
// request.setWithTsa(true);
// request.setEncryptedToken(encryptedToken);
// request.setBase64SourceData(base64SourceData);
// signdata(request);
// GetstampRequest getstampRequest = new GetstampRequest();
// getstampRequest.setRelBizNo(relBizNo);
// String getstamp = getstamp(getstampRequest);
SignDataRequest request = new SignDataRequest();
if (cloudSignProperties.getTestEnabled()) {
request.setBusinessOrgCode(cloudSignProperties.getTestBusinessOrgCode());
request.setBusinessSystemCode(cloudSignProperties.getTestBusinessSystemCode());
request.setBusinessSystemAppId(cloudSignProperties.getTestBusinessSystemAppId());
} else {
request.setBusinessOrgCode(cloudSignProperties.getBusinessOrgCode());
request.setBusinessSystemCode(cloudSignProperties.getBusinessSystemCode());
request.setBusinessSystemAppId(cloudSignProperties.getBusinessSystemAppld());
}
request.setBusinessTypeCode("007");
request.setWithTsa(true);
request.setEncryptedToken(encryptedToken);
request.setBase64SourceData(base64SourceData);
signdata(request);
GetstampRequest getstampRequest = new GetstampRequest();
getstampRequest.setRelBizNo(relBizNo);
String getstamp = getstamp(getstampRequest);
return base64SourceData;
}
......@@ -109,7 +127,7 @@ public class CloudsignService {
String json = OpenUtil.toJson(request);
try {
log.info("{}-入参:{}",logTip,json);
String response = HttpUtils.sendPostRequestAndParse(signdata, json, null);
String response = HttpUtils.sendPostRequestAndParse(buildUrl(cloudSignProperties.getSigndataUrl()), json, null);
log.info("{}-返回数据:{}",logTip,response);
if(ObjectUtil.isEmpty(response)){
throw new ServiceException("获取失败");
......@@ -132,7 +150,7 @@ public class CloudsignService {
String json = OpenUtil.toJson(request);
try {
log.info("{}-入参:{}",logTip,json);
String response = HttpUtils.sendPostRequestAndParse(getstamp, json, null);
String response = HttpUtils.sendPostRequestAndParse(buildUrl(cloudSignProperties.getGetstampUrl()), json, null);
log.info("{}-返回数据:{}",logTip,response);
if(ObjectUtil.isEmpty(response)){
throw new ServiceException("获取失败");
......@@ -148,4 +166,92 @@ public class CloudsignService {
throw new ServiceException("获取手写签名图片失败");
}
}
/**
* 检查云签状态
* @param request
*/
public QueryStatusResponse queryStatus(QueryStatusRequest request){
String logTip = "queryStatus";
String json = OpenUtil.toJson(request);
try {
log.info("{}-入参:{}",logTip,json);
String response = HttpUtils.sendPostRequestAndParse(buildUrl(cloudSignProperties.getQuerystatusUrl()), json, null);
log.info("{}-返回数据:{}",logTip,response);
if(ObjectUtil.isEmpty(response)){
throw new ServiceException("查询失败");
}
QueryStatusResponse queryStatusResponse = JSON.parseObject(response, QueryStatusResponse.class);
return queryStatusResponse;
} catch (Exception exception) {
log.error("查询云签状态失败,e:{}", exception.getMessage());
throw new ServiceException("查询失败");
}
}
/**
* 获取Base64编码证书
* @param request
*/
public GetCertInfoResponse getCertInfo(GetCertInfoRequest request){
String logTip = "getCertInfo";
String json = OpenUtil.toJson(request);
try {
log.info("{}-入参:{}",logTip,json);
String response = HttpUtils.sendPostRequestAndParse(buildUrl(cloudSignProperties.getGetcertinfoUrl()), json, null);
log.info("{}-返回数据:{}",logTip,response);
if(ObjectUtil.isEmpty(response)){
throw new ServiceException("查询失败");
}
GetCertInfoResponse getCertInfoResponse = JSON.parseObject(response, GetCertInfoResponse.class);
return getCertInfoResponse;
} catch (Exception exception) {
log.error("获取Base64编码证书失败,e:{}", exception.getMessage());
throw new ServiceException("查询失败");
}
}
/**
* 云签证书数字签名验证
* @param request
*/
public VerifyDataResponse verifyData(VerifyDataRequest request){
String logTip = "verifyData";
String json = OpenUtil.toJson(request);
try {
log.info("{}-入参:{}",logTip,json);
String response = HttpUtils.sendPostRequestAndParse(buildUrl(cloudSignProperties.getVerifydataUrl()), json, null);
log.info("{}-返回数据:{}",logTip,response);
if(ObjectUtil.isEmpty(response)){
throw new ServiceException("验证失败");
}
VerifyDataResponse verifyDataResponse = JSON.parseObject(response, VerifyDataResponse.class);
return verifyDataResponse;
} catch (Exception exception) {
log.error("云签证书数字签名验证失败,e:{}", exception.getMessage());
throw new ServiceException("验证失败");
}
}
/**
* 查询云签二维码扫码结果
* @param request
*/
public GetLoginResultResponse getLoginResult(GetLoginResultRequest request){
String logTip = "getLoginResult";
String json = OpenUtil.toJson(request);
try {
log.info("{}-入参:{}",logTip,json);
String response = HttpUtils.sendPostRequestAndParse(buildUrl(cloudSignProperties.getGetloginresultUrl()), json, null);
log.info("{}-返回数据:{}",logTip,response);
if(ObjectUtil.isEmpty(response)){
throw new ServiceException("查询失败");
}
GetLoginResultResponse getLoginResultResponse = JSON.parseObject(response, GetLoginResultResponse.class);
return getLoginResultResponse;
} catch (Exception exception) {
log.error("查询云签二维码扫码结果失败,e:{}", exception.getMessage());
throw new ServiceException("查询失败");
}
}
}
package com.jmai.physic.cloudsign;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "GenloginqrcodeRequest", description = "获取登录二维码请求参数")
public class GenloginqrcodeRequest {
@ApiModelProperty(value = "深圳市卫生计生组织机构代码,每个医院均有独立编码", required = true)
private String businessOrgCode;
@ApiModelProperty(value = "深圳市CA业务系统编码,每个业务系统均有独立编码", required = true)
private String businessSystemCode;
@ApiModelProperty(value = "业务系统应用ID,业务系统的唯一标识号", required = true)
private String businessSystemAppID;
@ApiModelProperty(value = "通知回调地址")
private String notifyUrl;
@ApiModelProperty(value = "二维码图片格式:1-JPG,2-PNG")
private Integer imageFormat;
}
package com.jmai.physic.cloudsign;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "GenloginqrcodeRespon", description = "获取登录二维码响应参数")
public class GenloginqrcodeRespon {
@ApiModelProperty(value = "状态码,非0表示执行失败")
private Integer statusCode;
@ApiModelProperty(value = "状态信息")
private String eventMsg;
@ApiModelProperty(value = "事件值对象")
private EventValue eventValue;
@Data
@ApiModel(value = "GenloginqrcodeRespon.EventValue", description = "事件值对象")
public static class EventValue {
@ApiModelProperty(value = "二维码图片Base64编码")
private String qRCodeBase64;
@ApiModelProperty(value = "二维码有效时长,单位秒")
private Integer durateTime;
@ApiModelProperty(value = "二维码唯一标识")
private String claimUuid;
@ApiModelProperty(value = "加密令牌")
private String encryptedToken;
}
}
package com.jmai.physic.cloudsign;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "GetCertInfoRequest", description = "获取Base64编码证书请求参数")
public class GetCertInfoRequest {
@ApiModelProperty(value = "深圳市卫生计生组织机构代码,每个医院均有独立编码", required = true)
private String businessOrgCode;
@ApiModelProperty(value = "云签账号", required = true)
private String relBizNo;
}
\ No newline at end of file
package com.jmai.physic.cloudsign;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "GetCertInfoResponse", description = "获取Base64编码证书响应参数")
public class GetCertInfoResponse {
@ApiModelProperty(value = "状态码,非0表示执行失败")
private Integer statusCode;
@ApiModelProperty(value = "状态信息")
private String eventMsg;
@ApiModelProperty(value = "事件值对象")
private EventValue eventValue;
@Data
@ApiModel(value = "GetCertInfoResponse.EventValue", description = "事件值对象")
public static class EventValue {
@ApiModelProperty(value = "base64编码格式证书")
private String base64Cert;
}
}
\ No newline at end of file
package com.jmai.physic.cloudsign;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "GetLoginResultRequest", description = "查询云签二维码扫码结果请求参数")
public class GetLoginResultRequest {
@ApiModelProperty(value = "深圳市卫生计生组织机构代码,每个医院均有独立编码", required = true)
private String businessOrgCode;
@ApiModelProperty(value = "深圳市CA业务系统编码,每个业务系统均有独立编码", required = true)
private String businessSystemCode;
@ApiModelProperty(value = "业务系统应用ID,业务系统的唯一标识号", required = true)
private String businessSystemAppID;
@ApiModelProperty(value = "云签登录任务的唯一标识,由301返回值获得")
private String claimUuid;
}
\ No newline at end of file
package com.jmai.physic.cloudsign;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "GetLoginResultResponse", description = "查询云签二维码扫码结果响应参数")
public class GetLoginResultResponse {
@ApiModelProperty(value = "状态码,非0表示执行失败")
private Integer statusCode;
@ApiModelProperty(value = "状态信息")
private String eventMsg;
@ApiModelProperty(value = "事件值对象")
private EventValue eventValue;
@Data
@ApiModel(value = "GetLoginResultResponse.EventValue", description = "事件值对象")
public static class EventValue {
@ApiModelProperty(value = "登录状态:1表示登录成功,不为1表示查询失败")
private String loginStatus;
@ApiModelProperty(value = "加密令牌,用于登录后的CA签名等操作使用")
private String encryptedToken;
@ApiModelProperty(value = "云签账号")
private String relBizNo;
}
}
\ No newline at end of file
package com.jmai.physic.cloudsign;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "GetstampRequest", description = "获取手写签名图片请求参数")
public class GetstampRequest {
@ApiModelProperty(value = "签章账号", required = true)
private String relBizNo;
}
package com.jmai.physic.cloudsign;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "GetstampRespon", description = "获取手写签名图片响应参数")
public class GetstampRespon {
@ApiModelProperty(value = "状态码,非0表示执行失败")
private Integer statusCode;
@ApiModelProperty(value = "状态信息")
private String eventMsg;
@ApiModelProperty(value = "事件值对象")
private EventValue eventValue;
@Data
@ApiModel(value = "GetstampRespon.EventValue", description = "事件值对象")
public static class EventValue {
@ApiModelProperty(value = "base64编码的签名图片")
private String stampBase64;
}
......
package com.jmai.physic.cloudsign;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "LoginBypinRequest", description = "PIN码登录请求参数")
public class LoginBypinRequest {
@ApiModelProperty(value = "深圳市卫生计生组织机构代码,每个医院均有独立编码", hidden = true)
private String businessOrgCode;
@ApiModelProperty(value = "深圳市 CA 业务系统编码,每个业务系统均有独立编码", hidden = true)
private String businessSystemCode;
private String businessSystemAppID;
@ApiModelProperty(value = "业务系统应用 ID,业务系统的唯一标识号", hidden = true)
private String businessSystemAppId;
@ApiModelProperty(value = "医生工号(当前用户工号)", hidden = true)
private String relBizNo;
@ApiModelProperty(value = "医生在业务系统输入的证书 PIN 码,进行 Base64 编码后的字符串。" +
"注意:云签数字证书申请成功后,医生手机上会收到 PIN 码,可通过云签 APP 进行修改。", required = true)
private String userEncodePin;
@ApiModelProperty(value = "登录方式,1 表示 PIN 码认证", required = true)
private Integer loginType;
}
package com.jmai.physic.cloudsign;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "PinLoginRequest", description = "PIN码登录请求参数")
public class PinLoginRequest {
@ApiModelProperty(value = "深圳市卫生计生组织机构代码,每个医院均有独立编码", hidden = true)
private String businessOrgCode;
@ApiModelProperty(value = "深圳市 CA 业务系统编码,每个业务系统均有独立编码", hidden = true)
private String businessSystemCode;
@ApiModelProperty(value = "业务系统应用 ID,业务系统的唯一标识号", hidden = true)
private String businessSystemAppId;
@ApiModelProperty(value = "医生工号(当前用户工号)", hidden = true)
private String relBizNo;
@ApiModelProperty(value = "医生在业务系统输入的证书 PIN 码,进行 Base64 编码后的字符串。" +
"注意:云签数字证书申请成功后,医生手机上会收到 PIN 码,可通过云签 APP 进行修改。", required = true)
private String userEncodePin;
@ApiModelProperty(value = "登录方式,1 表示 PIN 码认证", required = true)
private Integer loginType;
}
\ No newline at end of file
package com.jmai.physic.cloudsign;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "QRCodeLoginRequest", description = "二维码登录请求参数")
public class QRCodeLoginRequest {
@ApiModelProperty(value = "深圳市卫生计生组织机构代码,每个医院均有独立编码", required = true)
private String businessOrgCode;
@ApiModelProperty(value = "深圳市CA业务系统编码,每个业务系统均有独立编码", required = true)
private String businessSystemCode;
@ApiModelProperty(value = "业务系统应用ID,业务系统的唯一标识号", required = true)
private String businessSystemAppID;
@ApiModelProperty(value = "通知回调地址")
private String notifyUrl;
@ApiModelProperty(value = "二维码图片格式:1-JPG,2-PNG")
private Integer imageFormat;
}
\ No newline at end of file
package com.jmai.physic.cloudsign;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "QRCodeLoginResponse", description = "二维码登录响应参数")
public class QRCodeLoginResponse {
@ApiModelProperty(value = "状态码,非0表示执行失败")
private Integer statusCode;
@ApiModelProperty(value = "状态信息")
private String eventMsg;
@ApiModelProperty(value = "事件值对象")
private EventValue eventValue;
@Data
@ApiModel(value = "QRCodeLoginResponse.EventValue", description = "事件值对象")
public static class EventValue {
@ApiModelProperty(value = "二维码图片Base64编码")
private String qRCodeBase64;
@ApiModelProperty(value = "二维码有效时长,单位秒")
private Integer durateTime;
@ApiModelProperty(value = "二维码唯一标识")
private String claimUuid;
@ApiModelProperty(value = "加密令牌")
private String encryptedToken;
}
}
\ No newline at end of file
package com.jmai.physic.cloudsign;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "QueryStatusRequest", description = "检查云签状态请求参数")
public class QueryStatusRequest {
@ApiModelProperty(value = "深圳市卫生计生组织机构代码,每个医院均有独立编码", required = true)
private String businessOrgCode;
@ApiModelProperty(value = "深圳市CA业务系统编码,每个业务系统均有独立编码", required = true)
private String businessSystemCode;
@ApiModelProperty(value = "业务系统应用ID,业务系统的唯一标识号", required = true)
private String businessSystemAppID;
@ApiModelProperty(value = "加密口令,通过登录接口获取", required = true)
private String encryptedToken;
}
\ No newline at end of file
package com.jmai.physic.cloudsign;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "QueryStatusResponse", description = "检查云签状态响应参数")
public class QueryStatusResponse {
@ApiModelProperty(value = "状态码,非0表示执行失败")
private Integer statusCode;
@ApiModelProperty(value = "状态信息")
private String eventMsg;
@ApiModelProperty(value = "事件值对象")
private EventValue eventValue;
@Data
@ApiModel(value = "QueryStatusResponse.EventValue", description = "事件值对象")
public static class EventValue {
@ApiModelProperty(value = "加密令牌剩余有效时间,单位为秒;若加密令牌失效或已过期,值为-1")
private String time;
}
}
\ No newline at end of file
package com.jmai.physic.cloudsign;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "SignDataRequest", description = "云签证书数字签名请求参数")
public class SignDataRequest {
@ApiModelProperty(value = "深圳市卫生计生组织机构代码,每个医院均有独立编码", required = true)
private String businessOrgCode;
@ApiModelProperty(value = "深圳市CA业务系统编码,每个业务系统均有独立编码", required = true)
private String businessSystemCode;
private String businessSystemAppID;
@ApiModelProperty(value = "业务系统应用ID,业务系统的唯一标识号", required = true)
private String businessSystemAppId;
@ApiModelProperty(value = "业务类型代码", required = true)
private String businessTypeCode;
@ApiModelProperty(value = "加密令牌", required = true)
private String encryptedToken;
@ApiModelProperty(value = "患者ID")
private String patientId;
@ApiModelProperty(value = "业务ID")
private String bizId;
@ApiModelProperty(value = "待签名数据的Base64编码", required = true)
private String base64SourceData;
@ApiModelProperty(value = "是否包含时间戳")
private Boolean withTsa;
......
package com.jmai.physic.cloudsign;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "SignDataRespon", description = "云签证书数字签名响应参数")
public class SignDataRespon {
@ApiModelProperty(value = "状态码,非0表示执行失败")
private Integer statusCode;
@ApiModelProperty(value = "状态信息")
private String eventMsg;
@ApiModelProperty(value = "事件值对象")
private EventValue eventValue;
@Data
@ApiModel(value = "SignDataRespon.EventValue", description = "事件值对象")
public static class EventValue {
@ApiModelProperty(value = "签名数据")
private String signedData;
@ApiModelProperty(value = "时间戳")
private Integer timestamp;
}
}
package com.jmai.physic.cloudsign;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "VerifyDataRequest", description = "云签证书数字签名验证请求参数")
public class VerifyDataRequest {
@ApiModelProperty(value = "深圳市卫生计生组织机构代码,每个医院均有独立编码", required = true)
private String businessOrgCode;
@ApiModelProperty(value = "医生工号", required = true)
private String relBizNo;
@ApiModelProperty(value = "base64编码格式证书,通过304接口获取", required = true)
private String signCert;
@ApiModelProperty(value = "签名原文,与302接口传入的base64SourceData字段须一致", required = true)
private String sourceData;
@ApiModelProperty(value = "签名值", required = true)
private String signedData;
}
\ No newline at end of file
package com.jmai.physic.cloudsign;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "VerifyDataResponse", description = "云签证书数字签名验证响应参数")
public class VerifyDataResponse {
@ApiModelProperty(value = "状态码,非0表示执行失败")
private Integer statusCode;
@ApiModelProperty(value = "状态信息")
private String eventMsg;
}
\ No newline at end of file
医院云签webapi
(通用二维码登录)
接口文档
版本号:V2.4
撰写人:杨耀绥
联系电话:86-755-23972336
地址:深圳市大冲国际中心-B座1009
目录
第1章 引言 1
1.1 REST介绍 1
1.2 编写目的 1
1.3 编写原则 1
第2章 集成改造示例 3
2.1 云签证书登录应用集成说明 3
2.2 云签证书数字签名应用集成说明 3
第3章 接口详情 7
3.1 请求云签二维码 7
3.2 二维码扫码回调(业务系统实现) 9
3.3 查询云签二维码扫码结果 10
3.4 云签证书数字签名 12
3.5 获取手写签名图片 14
3.6 获取Base64编码证书 15
3.7 云签证书数字签名验证 16
3.8 查询云签加密令牌是否有效 17
第1章引言
1.1REST介绍
   REpresentational State Transfer (REST) 是一种架构原则,其中将 web 服务视为资源,可以由其 URL 唯一标识。RESTful Web 服务的关键特点是明确使用 HTTP 方法来表示不同的操作的调用。
   REST 的基本设计原则对典型 CRUD 操作使用 HTTP 协议方法:
   POST - 创建资源
   GET - 检索资源
   PUT – 更新资源
   DELETE - 删除资源
   REST 服务的主要优势在于:
   它们是跨平台 (Java、.net、PHP 等)高度可重用的,因为它们都依赖基本 HTTP 协议。
   它们使用基本的 XML,而不是复杂的 SOAP XML,使用非常方便。
   基于 REST 的 web 服务日益成为后端企业服务集成的首选方法。与基于 SOAP 的 web 服务相比,它的编程模型简单,而本机 XML(而不是 SOAP )的使用减少了序列化和反序列化过程的复杂性,并且不再需要其他作用相同的第三方库。
1.2编写目的
   编写本文的目的是为了将系统功能进行模块化、服务化,将用户的操作以服务的方式提供。系统与系统之间遵循服务规范,将系统与系统之间的交互转为定制化服务交互,以实现系统与系统之间的集成。
1.3编写原则
   可寻址性(Addressability)REST 中的所有东西都基于资源 的概念。资源与 OOP 中的对象或其他名词不同,它是一种抽象,必须可以通过 URI 寻址或访问。
   接口一致性(Interface uniformity)与 SOAP 或其他标准不同,REST 要求用来操纵资源的方法或动词不是任意的。这意味着 RESTful 服务的开发人员只能使用 HTTP 支持的方法,比如 GET、PUT、POST、DELETE 等等。因此不需要使用 WSDL 等服务描述语言。
   无状态(Statelessness)为了增强可伸缩性,服务器端不存储客户机的状态信息。这使服务器不与特定的客户机相绑定,负载平衡变得简单多了。这还让服务器更容易监视、更可靠。
   具象(Representational)客户机总是与资源的某种具象交互,绝不会直接与资源本身交互。同一资源还可以有多个具象。理论上说,持有资源的具象的任何客户机应该有操纵底层资源的足够信息。
   连通性(Connectedness)任何基于 REST 的系统都应该预见到客户机需要访问相关的资源,应该在返回的资源具象中包含这些资源。例如,可以以超链接的形式包含特定 RESTful 服务的操作序列中的相关步骤,让客户机可以根据需要访问它们。基于 REST 的 Web 服务日益成为后端企业服务集成的。
第2章集成改造示例
2.1云签证书登录应用集成说明
  当医务人员通过医院统一门户登录时,统一门户应集成云签webapi接口,实现基于云签证书与云签二维码的强身份认证登录。
   统一门户系统开发商在门户登录页面集成云签登录,参考界面如下:
   流程如下:
1)统一门户系统首先调用“请求云签二维码”展示云签二维码;
2)医务人员使用云签APP扫描云签二维码输入云签证书PIN码;
3)统一门户系统展示云签二维码后,定时调用系统后台接口(业务系统自行定义)。统一门户系统开发商需改造系统后台,调用“查询云签二维码扫码结果”接口获取登录结果,或者“实现二维码扫码回调”;
4)统一门户系统根据“查询云签二维码扫码结果”接口或者“实现二维码扫码回调”获取的用户信息,调整至相关用户权限页面。
5)完成登录流程。
2.2云签证书数字签名应用集成说明
   为确保医疗数据具有法律效力,必须按照《电子签名法》要求,基于由国家认可的第三方电子认证服务机构签发的数字证书对其完成数字签名,才能具有法律效力。因此,医院移动端医疗信息系统需通过集成移动医疗云签署实现数字签名,以及数字签名的签名验证加盖时间戳等功能。
   医院移动端医疗信息系统需要在数据库对应业务的数据表中增加数字签名值字段和签名者数字证书字段(或者新建数据表)以及时间戳签名值字段,建立数字签名、签名者证书、对应原始明文和时间戳签名值的一一映射关系,为事后责任认定提供符合法律要求的电子证据。
   具体流程如下图所示:
  流程说明:
1)用户登录医院移动端医疗信息系统前端后,书写处方后,点“签名”按钮;
2)医院移动端医疗信息系统服务端判断该用户是否已输入CA密码认证过(存在加密令牌encryptedToken);
3)若不存在加密令牌,则返回前端弹出提示用户输入CA密码的窗口,用户输入密码后,医院移动端医疗信息系统服务调用“PIN码获取令牌”接口获取加密令牌,并将加密令牌保存至内存或缓存数据库,执行步骤5。
4)若存在加密令牌,则直接使用加密令牌,执行步骤5。
5)医院移动端医疗信息系统服务端调用“数据签名接口”对进行Base64编码后的内容执行电子签名;
6)如果签名成功,将电子病历签名原文、Base64编码签名原文、签名值、时间戳签名结果关联保存在后台数据库中,同时,前端提示签名完成。
7)为方便用户直观感受到签名结果,在签名完成后,医院移动端医疗信息系统需要获取用户的手写签名图片展示至系统页面。
8)如果签名失败,则将错误返回至前端进行提示,同时删除加密令牌。
  注意:用户在医院移动端医疗信息系统前端执行退出时,医院移动端医疗信息系统服务端要删除加密令牌。
第3章接口详情
3.1请求云签二维码
编号 301
请求方式 POST
服务路径 公网测试地址:
http://www.jztech.top:18087/v1.0/cloudsign/genloginqrcode
http://www.jztech.top:18077/v1.0/cloudsign/genloginqrcode
路径参数/描述 无
参数类型 application/json
参数描述 参数:
属性 类型 是否必选 说明
businessOrgCode String 是 深圳市卫生计生组织机构代码,每个医院均有独立编码,详情请联系CA技术支持,QQ:1798794512;开发时可在公网进行,测试请使用"455767873";医院联调测试请使用医院的组织机构编码
businessSystemCode String 是 深圳市CA业务系统编码,每个业务系统均有独立编码,详情请联系CA技术支持,QQ:1798794512;开发时可在公网进行,测试请使用"9998";医院联调测试请使用正确的业务系统编码
businessSystemAppID String 是 业务系统应用ID,业务系统的唯一标识号。每个业务系统均有独立应用ID,详情请联系CA技术支持,QQ:1798794512;开发时可在公网进行,测试请使用"o7d7q8ehm4tkrc6o";医院联调测试请使用正确的业务系统应用ID
notifyUrl String 否 业务系统定义的回调url
imageFormat Number 否 图片格式,2表示BMP
格式示例:
{
"businessOrgCode":"455767873",
"businessSystemCode":"9998",
"businessSystemAppID":"o7d7q8ehm4tkrc6o",
"notifyUrl":"http://www.jztech.top:18087/login/notify",
"imageFormat":2
}
返回值类型 application/json
描述 出参:
属性 类型 说明
statusCode Number 状态码不为0表示执行失败
eventMsg String 状态信息
eventValue Object 属性 类型 说明
qRCodeBase64 String CA登录二维码
durateTime Number 有效时长,单位:秒
claimUuid String 此次登录任务的唯一标识
请求云签二维码成功,返回格式为:
{
"statusCode":0,
"eventMsg":"生成二维码相关信息成功.",
"eventValue":{
"qRCodeBase64":"MIIGtAYJKoZIhvcNANTc......",
"durateTime":120,
"claimUuid":"0bcbab8c75024de380b50f9a35615264"
}
}
请求云签二维码失败,返回格式为:
{
"statusCode":-11,
"eventMsg":"处理登录二维码请求失败, 系统异常."
}
3.2二维码扫码回调(业务系统实现)
编号 302
请求方式 POST
服务路径 301请求参数notifyUrl,由业务系统确定
路径参数/描述 无
参数类型 application/json
参数描述 入参:
属性 类型 是否必选 说明
claimUuid String 是 此次登录任务的唯一标识,通301返回值
loginStatus String 是 登录状态:
0表示登录成功,
1表示登录失败,
2表示取消登录
relBizNo String 是 云签账号
encryptedToken String 否 加密令牌,用于登录后的CA签名等操作使用
格式示例:
{
"claimUuid":"0bcbab8c75024de380b50f9a35615264",
"loginStatus":0,
"relBizNo":"0644",
"encryptedToken":"NzVFQzU1N0UyNDM0N..."
}
返回值类型 application/json
描述 出参:
属性 类型 说明
statusCode Number 状态码不为0表示执行失败
eventMsg String 状态信息
回调执行成功,返回格式为:
{
"statusCode":0,
"eventMsg":"回调通知成功.",
}
回调执行失败,返回格式为:
{
"statusCode":-11,
"eventMsg":"处理登录二维码请求失败, 系统异常."
}
3.3查询云签二维码扫码结果
编号 303
请求方式 POST
服务路径 公网测试地址:
http://www.jztech.top:18087/v1.0/cloudsign/getLoginResult/web
http://www.jztech.top:18077/v1.0/cloudsign/getLoginResult/web
路径参数/描述 无
参数类型 application/json
参数描述 入参:
属性 类型 是否必选 说明
businessOrgCode String 是 深圳市卫生计生组织机构代码,每个医院均有独立编码,详情请联系CA技术支持,QQ:1798794512;开发时可在公网进行,测试请使用"455767873";医院联调测试请使用医院的组织机构编码
businessSystemCode String 是 深圳市CA业务系统编码,每个业务系统均有独立编码,详情请联系CA技术支持,QQ:1798794512;开发时可在公网进行,测试请使用"9998";医院联调测试请使用正确的业务系统编码
businessSystemAppID String 是 业务系统应用ID,业务系统的唯一标识号。每个业务系统均有独立应用ID,详情请联系CA技术支持,QQ:1798794512;开发时可在公网进行,测试请使用"o7d7q8ehm4tkrc6o";医院联调测试请使用正确的业务系统应用ID
claimUuid String 否 云签登录任务的唯一标识,由301返回值获得
格式示例:
{
"businessOrgCode":"455767873",
"businessSystemCode":"9998",
"businessSystemAppID":"o7d7q8ehm4tkrc6o",
"claimUuid": "cloudsign-a4e0b0bbf8614cdf95a6f1f88e007774"
}
返回值类型 application/json
描述 出参:
属性 类型 说明
statusCode Number 状态码不为0表示执行失败
eventMsg String 状态信息
eventValue Object 属性 类型 说明
loginStatus String 登录状态:1表示登录成功,不为1表示查询失败
encryptedToken String 加密令牌,用于登录后的CA签名等操作使用
relBizNo String 云签账号
请求云签二维码扫码结果成功且扫码成功,返回格式为:
{
"statusCode":0,
"eventMsg":"二维码扫码成功.",
"eventValue":{
"loginStatus":1,
"encryptedToken":"NzVFQzU1N0UyNDM0N..."
"relBizNo":"0644"
}
}
请求云签二维码扫码结果成功但扫码失败,返回格式为:
{
"statusCode": 0,
"eventMsg": "云签署数字证书未关联用户,请联系管理员处理.",
"eventValue": {
"loginStatus":-31,
"relBizNo": "0644"
}
}
请求云签二维码扫码结果成功但用户未扫码,返回格式为:
{
    "statusCode": -99,
    "eventMsg": "云签结果未返回, 请等待用户操作。"
}
请求云签二维码扫码结果失败,返回格式为:
{
    "statusCode": -11,
    "eventMsg": "入参claimUuid为空!请检查后重试。"
}
3.4云签证书数字签名
编号 304
请求方式 POST
服务路径 公网测试地址:
http://www.jztech.top:18087/v1.0/cloudsign/signdata
http://www.jztech.top:18077/v1.0/cloudsign/signdata
路径参数/描述 无
参数类型 application/json
参数描述 入参:
属性 类型 是否必选 说明
businessOrgCode String 是 深圳市卫生计生组织机构代码,每个医院均有独立编码,详情请联系CA技术支持,QQ:1798794512;开发时可在公网进行,测试请使用"455767873";医院联调测试请使用医院的组织机构编码
businessSystemCode String 是 深圳市CA业务系统编码,每个业务系统均有独立编码,详情请联系CA技术支持,QQ:1798794512;开发时可在公网进行,测试请使用"9998";医院联调测试请使用正确的业务系统编码
businessSystemAppID String 是 业务系统应用ID,业务系统的唯一标识号。每个业务系统均有独立应用ID,详情请联系CA技术支持,QQ:1798794512;开发时可在公网进行,测试请使用"o7d7q8ehm4tkrc6o";医院联调测试请使用正确的业务系统应用ID
businessTypeCode String 是 深圳市CA业务类型编码
值 值含义
001 登录
002 处方
003 医嘱
004 检验
005 检查
006 病历
007 审批
998 测试
999 其他
encryptedToken String 是 加密口令,通过301接口获取
patientId String 否 病人id
bizId String 否 业务系统id
base64SourceData String 是 签名原文,需要进行base64编码
withTsa Boolean 是 是否进行时间戳签名
格式示例:
{
"businessOrgCode":"455767873",
"businessSystemCode":"9998",
"businessSystemAppID":"o7d7q8ehm4tkrc6o",
"businessTypeCode":"998",
"encryptedToken":"ODA2MDAwMTEyNTc1N……",
"patientId":"10001",
"bizId":"2001817",
"base64SourceData":"562-5ZCN5Y6f5paH",
"withTsa":true
}
返回值类型 application/json
描述 出参:
属性 类型 说明
statusCode Number 状态码不为0表示执行失败
eventMsg String 状态信息
eventValue Object 属性 类型 说明
signedData String 签名值
timestamp String 时间戳签名值
数据签名成功,返回格式为:
{
"statusCode":0,
"eventMsg":"数据签名成功.",
"eventValue":{
"signedData":"MIIGMQYJKoZIhvcNAQcCo......",
"timestamp":"MIIGtAYJKoZIhvcNAQcCoI......"
}
}
数据签名失败,返回格式为:
{
"statusCode":-11,
"eventMsg":"数据签名失败: 无效加密令牌."
}
3.5获取手写签名图片
编号 305
请求方式 POST
服务路径 公网测试地址:
http://www.jztech.top:18087/v1.0/cloudsign/getstamp
http://www.jztech.top:18077/v1.0/cloudsign/getstamp
路径参数/描述 无
参数类型 application/json
参数描述 入参:
属性 类型 是否必选 说明
relBizNo String 是 云签账号
格式示例:
{
"businessOrgCode":"455767873",
"relBizNo":"0644"
}
返回值类型 application/json
描述 出参:
属性 类型 说明
statusCode Number 状态码不为0表示执行失败
eventMsg String 状态信息
eventValue Object 属性 类型 说明
stampBase64 String base64编码格式签章图片
获取手写签名图片成功,返回格式为:
{
"statusCode":0,
"eventMsg":"获取手写签名图片成功.",
"eventValue":{
"stampBase64":"iVBORw0KGgoAAAANSUhE......"
}
}
获取手写签名图片失败,返回格式为:
{
"statusCode":-11,
"eventMsg":"获取手写签名图片失败,无效云签账号."
}
3.6获取Base64编码证书
编号 304
请求方式 POST
服务路径 公网测试地址:
http://www.jztech.top:18087/v1.0/cloudsign/getcertinfo
http://www.jztech.top:18077/v1.0/cloudsign/getcertinfo
路径参数/描述 无
参数类型 application/json
参数描述 入参:
属性 类型 是否必选 说明
relBizNo String 是 云签账号
格式示例:
{
"businessOrgCode":"455767873",
"relBizNo":"0644"
}
返回值类型 application/json
描述 出参:
属性 类型 说明
statusCode Number 状态码不为0表示执行失败
eventMsg String 状态信息
eventValue Object 属性 类型 说明
base64Cert String base64编码格式证书
获取base64编码格式证书成功,返回格式为:
{
"statusCode":0,
"eventMsg":"获取base64编码格式证书成功.",
"eventValue":{
"base64Cert":"MIIE4zCCA8ugAwIBAgIKGzAA......",
}
}
获取base64编码格式证书失败,返回格式为:
{
"statusCode":-11,
"eventMsg":"获取base64编码格式证书失败,无效云签账号."
}
3.7云签证书数字签名验证
编号 305
请求方式 POST
服务路径 公网测试地址:
http://www.jztech.top:18087/v1.0/cloudsign/verify/data
http://www.jztech.top:18077/v1.0/cloudsign/verify/data
路径参数/描述 无
参数类型 application/json
参数描述 入参:
属性 类型 是否必选 说明
businessOrgCode String 是 深圳市卫生计生组织机构代码,每个医院均有独立编码,详情请联系CA技术支持,QQ:1798794512;开发时可在公网进行,测试请使用"455767873";医院联调测试请使用医院的组织机构编码
relBizNo String 是 医生工号
signCert String 是 base64编码格式证书,通过304接口获取
sourceData String 是 签名原文,与302接口传入的base64SourceData字段须一致
signedData String 是 签名值
格式示例:
{
"businessOrgCode":"455767873",
"relBizNo":"0644",
"signCert":"MIIE4zCCA8ugAwIBAgIKGzAA......",
"sourceData":"562-5ZCN5Y6f5paH",
"signedData":"MIIGMQYJKoZIhvcNAQcCo......"
}
返回值类型 application/json
描述 出参:
属性 类型 说明
statusCode Number 状态码不为0表示执行失败
eventMsg String 状态信息
数据签名验证成功,返回格式为:
{
"statusCode":0,
"eventMsg":"数据签名验证成功."
}
数据签名验证失败,返回格式为:
{
"statusCode":-11,
"eventMsg":"数据签名验证失败: 无效base64编码格式证书."
}
3.8查询云签加密令牌是否有效
编号 306
请求方式 POST
服务路径 公网测试地址:
http://www.jztech.top:18087/v1.0/cloudsign/usertoken/queryStatus
http://www.jztech.top:18077/v1.0/cloudsign/usertoken/queryStatus
路径参数/描述 无
参数类型 application/json
参数描述 入参:
属性 类型 是否必选 说明
businessOrgCode String 是 深圳市卫生计生组织机构代码,每个医院均有独立编码,详情请联系CA技术支持,QQ:1798794512;开发时可在公网进行,测试请使用"455767873";医院联调测试请使用医院的组织机构编码
businessSystemCode String 是 深圳市CA业务系统编码,每个业务系统均有独立编码,详情请联系CA技术支持,QQ:1798794512;开发时可在公网进行,测试请使用"9998";医院联调测试请使用正确的业务系统编码
businessSystemAppID String 是 业务系统应用ID,业务系统的唯一标识号。每个业务系统均有独立应用ID,详情请联系CA技术支持,QQ:1798794512;开发时可在公网进行,测试请使用"o7d7q8ehm4tkrc6o";医院联调测试请使用正确的业务系统应用ID
encryptedToken String 是 加密口令,通过301接口获取
格式示例:
{
"businessOrgCode":"455767873",
"businessSystemCode":"9998",
"businessSystemAppID":"o7d7q8ehm4tkrc6o",
"encryptedToken":"ODA2MDAwMTEyNTc1N……"
}
返回值类型 application/json
描述 出参:
属性 类型 说明
statusCode Number 状态码不为0表示执行失败
eventMsg String 状态信息
eventValue Object 属性 类型 说明
time String 加密令牌剩余有效时间,单位为秒
若加密令牌失效或已过期,值为-1
查询云签加密令牌成功,返回格式为:
{
"statusCode":0,
"eventMsg":"云签加密令牌有效."
"eventValue":{
"time":"1800"
}
}
查询云签加密令牌失败,返回格式为:
{
"statusCode":-21,
"eventMsg":"身份未认证或认证已超时."
}
package com.jmai.physic.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
......@@ -8,8 +9,108 @@ import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "cloudsign")
public class CloudSignProperties {
/**
* 云签名服务基础地址
*/
private String host = "http://192.168.2.194:18087";
/**
* 深圳市卫生计生组织机构代码,每个医院均有独立编码
*/
private String businessOrgCode;
/**
* 深圳市 CA 业务系统编码,每个业务系统均有独立编码
*/
private String businessSystemCode;
private String businessSystemApplD;
/**
* 业务系统应用 ID,业务系统的唯一标识号
*/
private String businessSystemAppld;
/**
* 登录方式,1-PIN码认证
*/
private Integer loginType = 1;
//=========================================
/**
* 是否启用测试:true表示启用测试,false表示不启用测试(默认为false)
*/
private Boolean testEnabled = false;
/**
* 测试用的组织机构代码
*/
private String testBusinessOrgCode = "455767873";
/**
* 测试用的业务系统编码
*/
private String testBusinessSystemCode = "9998";
/**
* 测试用的业务系统应用ID
*/
private String testBusinessSystemAppId = "o7d7q8ehm4tkrc6o";
/**
* 测试用的医生工号
*/
@Deprecated
private String testRelBizNo = "WN123456";
/**
* 测试用的用户编码PIN码
*/
@Deprecated
private String testUserEncodePin = "MTIzNDU2";
//=========================================
// 云签名API端点配置
//=========================================
/**
* PIN码登录接口
*/
private String pinloginUrl = "/v1.0/cloudsign/loginbypin";
/**
* 生成登录二维码接口
*/
private String genloginqrcodeUrl = "/v1.0/cloudsign/genloginqrcode";
/**
* 二维码登录接口
*/
private String qrcodeloginUrl = "/v1.0/cloudsign/genloginqrcode";
/**
* 签名数据接口
*/
private String signdataUrl = "/v1.0/cloudsign/signdata";
/**
* 获取印章接口
*/
private String getstampUrl = "/v1.0/cloudsign/getstamp";
/**
* 查询用户令牌状态接口
*/
private String querystatusUrl = "/v1.0/cloudsign/usertoken/queryStatus";
/**
* 获取登录结果接口
*/
private String getloginresultUrl = "/v1.0/cloudsign/getLoginResult/web";
/**
* 获取证书信息接口
*/
private String getcertinfoUrl = "/v1.0/cloudsign/getcertinfo";
/**
* 验证数据接口
*/
private String verifydataUrl = "/v1.0/cloudsign/verify/data";
}
package com.jmai.physic.controller;
import com.jmai.physic.cloudsign.CloudsignService;
import com.jmai.physic.cloudsign.GenloginqrcodeRespon;
import com.jmai.physic.cloudsign.LoginBypinRequest;
import cn.hutool.core.util.ObjectUtil;
import com.jmai.api.exception.ServiceException;
import com.jmai.physic.cloudsign.*;
import com.jmai.physic.cloudsign.QRCodeLoginRequest;
import com.jmai.physic.cloudsign.QRCodeLoginResponse;
import com.jmai.physic.config.CloudSignProperties;
import com.jmai.sys.aop.Auth;
import com.jmai.sys.ctx.SpringContextUtils;
import com.jmai.sys.dto.ResponseData;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
......@@ -14,6 +19,8 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@Auth
@Slf4j
@RestController
@RequestMapping("/cloudsign")
......@@ -21,13 +28,165 @@ import javax.annotation.Resource;
public class CloudSignController {
@Resource
private CloudsignService cloudsignService;
@Resource
private CloudSignProperties cloudSignProperties;
@PostMapping("/queryStatus")
@ApiOperation(value = "检查云签状态")
public ResponseData<QueryStatusResponse> queryStatus(@RequestBody QueryStatusRequest queryStatusRequest) {
String workNo = SpringContextUtils.getWorkNo();
if (ObjectUtil.isEmpty(workNo)) {
throw new ServiceException("当前用户工号为空");
}
queryStatusRequest.setBusinessOrgCode(cloudSignProperties.getBusinessOrgCode());
queryStatusRequest.setBusinessSystemCode(cloudSignProperties.getBusinessSystemCode());
queryStatusRequest.setBusinessSystemAppID(cloudSignProperties.getBusinessSystemAppld());
if (cloudSignProperties.getTestEnabled()) {
queryStatusRequest.setBusinessOrgCode(cloudSignProperties.getTestBusinessOrgCode());
queryStatusRequest.setBusinessSystemCode(cloudSignProperties.getTestBusinessSystemCode());
queryStatusRequest.setBusinessSystemAppID(cloudSignProperties.getTestBusinessSystemAppId());
} else {
queryStatusRequest.setBusinessOrgCode(cloudSignProperties.getBusinessOrgCode());
queryStatusRequest.setBusinessSystemCode(cloudSignProperties.getBusinessSystemCode());
queryStatusRequest.setBusinessSystemAppID(cloudSignProperties.getBusinessSystemAppld());
}
QueryStatusResponse queryStatus = cloudsignService.queryStatus(queryStatusRequest);
return ResponseData.ok(queryStatus);
}
@PostMapping("/loginByPin")
@ApiOperation(value = "PIN码登录")
public ResponseData<GenloginqrcodeRespon> loginByPin(@RequestBody PinLoginRequest pinLoginRequest) {
String workNo = SpringContextUtils.getWorkNo();
if (ObjectUtil.isEmpty(workNo)) {
throw new ServiceException("当前用户工号为空");
}
pinLoginRequest.setRelBizNo(workNo);
pinLoginRequest.setUserEncodePin(pinLoginRequest.getUserEncodePin());
if (cloudSignProperties.getTestEnabled()) {
pinLoginRequest.setBusinessOrgCode(cloudSignProperties.getTestBusinessOrgCode());
pinLoginRequest.setBusinessSystemCode(cloudSignProperties.getTestBusinessSystemCode());
pinLoginRequest.setBusinessSystemAppId(cloudSignProperties.getTestBusinessSystemAppId());
} else {
pinLoginRequest.setBusinessOrgCode(cloudSignProperties.getBusinessOrgCode());
pinLoginRequest.setBusinessSystemCode(cloudSignProperties.getBusinessSystemCode());
pinLoginRequest.setBusinessSystemAppId(cloudSignProperties.getBusinessSystemAppld());
}
GenloginqrcodeRespon pinLogin = cloudsignService.pinLogin(pinLoginRequest);
return ResponseData.ok(pinLogin);
}
@PostMapping("/loginByQrcode")
@ApiOperation(value = "二维码登录")
public ResponseData<QRCodeLoginResponse> loginByQrcode(@RequestBody QRCodeLoginRequest qrCodeLoginRequest) {
String workNo = SpringContextUtils.getWorkNo();
if (ObjectUtil.isEmpty(workNo)) {
throw new ServiceException("当前用户工号为空");
}
if (cloudSignProperties.getTestEnabled()) {
qrCodeLoginRequest.setBusinessOrgCode(cloudSignProperties.getTestBusinessOrgCode());
qrCodeLoginRequest.setBusinessSystemCode(cloudSignProperties.getTestBusinessSystemCode());
qrCodeLoginRequest.setBusinessSystemAppID(cloudSignProperties.getTestBusinessSystemAppId());
} else {
qrCodeLoginRequest.setBusinessOrgCode(cloudSignProperties.getBusinessOrgCode());
qrCodeLoginRequest.setBusinessSystemCode(cloudSignProperties.getBusinessSystemCode());
qrCodeLoginRequest.setBusinessSystemAppID(cloudSignProperties.getBusinessSystemAppld());
}
QRCodeLoginResponse qrCodeLogin = cloudsignService.qrCodeLogin(qrCodeLoginRequest);
return ResponseData.ok(qrCodeLogin);
}
@PostMapping("/loginByQrcode/callback")
@ApiOperation(value = "二维码登录回调")
public ResponseData<CloudSignCallbackResponse> loginByQrcodeCallback(@RequestBody CloudSignCallbackRequest callbackRequest) {
log.info("接收到云签登录回调,claimUuid: {}, loginStatus: {}, relBizNo: {}",
callbackRequest.getClaimUuid(), callbackRequest.getLoginStatus(), callbackRequest.getRelBizNo());
try {
// 处理登录回调逻辑
// 这里可以根据登录状态更新用户登录状态或执行其他业务逻辑
// 示例逻辑:
// 1. 根据claimUuid找到对应的登录请求
// 2. 根据loginStatus处理不同状态(登录成功、失败、取消)
// 3. 如果登录成功,保存加密令牌encryptedToken供后续使用
// 构造响应
CloudSignCallbackResponse response = new CloudSignCallbackResponse();
response.setStatusCode(0);
response.setEventMsg("回调通知成功.");
return ResponseData.ok(response);
} catch (Exception e) {
log.error("处理云签登录回调失败", e);
CloudSignCallbackResponse response = new CloudSignCallbackResponse();
response.setStatusCode(-11);
response.setEventMsg("处理登录二维码请求失败, 系统异常.");
return ResponseData.ok(response);
}
}
@PostMapping("/getLoginByQrcodeResult")
@ApiOperation(value = "查询二维码扫码结果")
public ResponseData<GetLoginResultResponse> getLoginByQrcodeResult(@RequestBody GetLoginResultRequest getLoginResultRequest) {
String workNo = SpringContextUtils.getWorkNo();
if (ObjectUtil.isEmpty(workNo)) {
throw new ServiceException("当前用户工号为空");
}
@PostMapping("/loginbypin")
@ApiOperation(value = "查询药品申请审核单")
public ResponseData<GenloginqrcodeRespon> loginbypin(@RequestBody LoginBypinRequest loginBypinRequest) {
GenloginqrcodeRespon loginbypin = cloudsignService.loginbypin(loginBypinRequest);
return ResponseData.ok(loginbypin);
if (cloudSignProperties.getTestEnabled()) {
getLoginResultRequest.setBusinessOrgCode(cloudSignProperties.getTestBusinessOrgCode());
getLoginResultRequest.setBusinessSystemCode(cloudSignProperties.getTestBusinessSystemCode());
getLoginResultRequest.setBusinessSystemAppID(cloudSignProperties.getTestBusinessSystemAppId());
} else {
getLoginResultRequest.setBusinessOrgCode(cloudSignProperties.getBusinessOrgCode());
getLoginResultRequest.setBusinessSystemCode(cloudSignProperties.getBusinessSystemCode());
getLoginResultRequest.setBusinessSystemAppID(cloudSignProperties.getBusinessSystemAppld());
}
GetLoginResultResponse getLoginResult = cloudsignService.getLoginResult(getLoginResultRequest);
return ResponseData.ok(getLoginResult);
}
@PostMapping("/getCertInfo")
@ApiOperation(value = "获取Base64编码证书")
public ResponseData<GetCertInfoResponse> getCertInfo(@RequestBody GetCertInfoRequest getCertInfoRequest) {
String workNo = SpringContextUtils.getWorkNo();
if (ObjectUtil.isEmpty(workNo)) {
throw new ServiceException("当前用户工号为空");
}
if (cloudSignProperties.getTestEnabled()) {
getCertInfoRequest.setBusinessOrgCode(cloudSignProperties.getTestBusinessOrgCode());
} else {
getCertInfoRequest.setBusinessOrgCode(cloudSignProperties.getBusinessOrgCode());
}
GetCertInfoResponse getCertInfo = cloudsignService.getCertInfo(getCertInfoRequest);
return ResponseData.ok(getCertInfo);
}
@PostMapping("/verifyData")
@ApiOperation(value = "云签证书数字签名验证")
public ResponseData<VerifyDataResponse> verifyData(@RequestBody VerifyDataRequest verifyDataRequest) {
String workNo = SpringContextUtils.getWorkNo();
if (ObjectUtil.isEmpty(workNo)) {
throw new ServiceException("当前用户工号为空");
}
if (cloudSignProperties.getTestEnabled()) {
verifyDataRequest.setBusinessOrgCode(cloudSignProperties.getTestBusinessOrgCode());
} else {
verifyDataRequest.setBusinessOrgCode(cloudSignProperties.getBusinessOrgCode());
}
VerifyDataResponse verifyData = cloudsignService.verifyData(verifyDataRequest);
return ResponseData.ok(verifyData);
}
}
......@@ -156,6 +156,7 @@ public class AuthAspect extends AbstractService {
SpringContextUtils.set(USER_ID, userToken.getUserId().toString());
SpringContextUtils.set(USER_NAME, userToken.getUserName());
SpringContextUtils.set(USER_TYPE, userToken.getUserType().toString());
SpringContextUtils.set(WORK_NO, userToken.getWorkNo());
SpringContextUtils.set(DEPT_ID, userToken.getDeptId().toString());
SpringContextUtils.set(AUTH_DEPT_LIST, userToken.getAuthDeptList());
SpringContextUtils.set(ROLE_LIST, userToken.getRoleList());
......
......@@ -37,6 +37,7 @@ public interface HeaderCode {
String USER_ID = "User-Id";
String USER_NAME = "User-Name";
String USER_TYPE = "User-Type";
String WORK_NO = "Work-No";
String DEPT_ID = "Dept-Id";
String AUTH_DEPT_LIST = "Auth-Dept-List";
String ROLE_LIST = "Role-List";
......
......@@ -173,6 +173,9 @@ public class SpringContextUtils implements ApplicationContextAware {
public static String getUserName() {
return get(HeaderCode.USER_NAME);
}
public static String getWorkNo() {
return get(HeaderCode.WORK_NO);
}
public static Long getUserType() {
String value = get(HeaderCode.USER_TYPE);
return Optional.ofNullable(value)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment