浙里办微信小程序上架
创始人
2024-02-12 06:28:42

一、概述

本指南旨在为“浙里办”单点登录组件提供接入指南,“浙里办”单点登陆组件,上架在IRS,为上架在IRS的应用,提供统一的单点登录解决方案,现阶段仅支持微信端的接入。

二、服务创建

IRS 应用管理员在 IRS 应用发布服务侧进行“应用发布注册”。 注意事项 1、IRS 应用系统查询没有应用信息,可通过 IRS 应用编目查询该应用的 IRS 应用管理员 信息。 2、IRS 应用管理员添加的开发商信息需要有浙政钉账号,由服务侧应用建设单位提供, 用于 IRS 应用发布开发商工作台进行服务部署。

3、应用接入“浙里办”单点登录组件前,需要先获取AK&SK。

 

三、接入说明

接入前需要服务侧应用建设单位已完成在 IRS 应用编目工作。从开发部署到服务上架,需 要经历以下主要阶段:

 

四、接入规范

  1. 接入“浙里办”微信小程序的 H5 应用(以下简称应用), 应当符合“同源发布”及无障碍适老化等要求。
  2. 应用应当在浙江省一体化数字资源系统(以下简称 IRS)发布,并使用统一的域名 https://mapi.zjzwfw.gov.cn/,作为接入微信小程序的前置条件。应用上架 IRS,应遵循 IRS 相关规范。
  3. 应用接入“浙里办”微信小程序,应当按照本指南操作步骤与注意事项,进行微信端的兼容适配。

五、操作步骤

“浙里办”微信小程序接入工作流程图:

1、单点登录适配 

Java代码案例:

(1)Constants  定义所有常量

/*** @author jie.chen* @date 2022-03-30 15:24*/
public interface Constants {/*** 单点登录 ticketId换token的地址*/
//    String ACCESS_TOKEN_URL = "https://bcdsg.zj.gov.cn:8443/restapi/prod/IC33000020220329000007/uc/sso/access_token";政务外网//互联网String ACCESS_TOKEN_URL = "https://ibcdsg.zj.gov.cn:8443/restapi/prod/IC33000020220329000007/uc/sso/access_token";/*** 单点登录 token获取用户信息地址*/
//    String GET_USER_INFO_URL = "https://bcdsg.zj.gov.cn:8443/restapi/prod/IC33000020220329000008/uc/sso/getUserInfo";政务外网//互联网String GET_USER_INFO_URL = "https://ibcdsg.zj.gov.cn:8443/restapi/prod/IC33000020220329000008/uc/sso/getUserInfo";/*** IRS请求携带的请求头*/String X_BG_HMAC_ACCESS_KEY = "X-BG-HMAC-ACCESS-KEY";String X_BG_HMAC_SIGNATURE = "X-BG-HMAC-SIGNATURE";String X_BG_HMAC_ALGORITHM = "X-BG-HMAC-ALGORITHM";String X_BG_DATE_TIME = "X-BG-DATE-TIME";/*** IRS签名算法*/String DEFAULT_HMAC_SIGNATURE = "hmac-sha256";/*** 应用ID*/String APP_ID = "20******33";/*** 微信端固定值为weixin*/String WEIXIN_ENDPOINT_TYPE = "weixin";/*** IRS 申请组件生成的AK*/String IRS_AK = "********************************";/*** IRS 申请组件生成的SK*/String IRS_SK = "********************************";String TOKEN_SESSION_KEY = "sessionAccessToken";String USER_INFO_KEY = "sessionUserInfo";}

(2)IrsUtils

/*** @author jie.chen* @date 2022-03-30 15:28*/
public class IrsUtils {@SneakyThrowspublic static IrsSignRes sign(String url, String method) {UriComponents uriComponents = UriComponentsBuilder.fromHttpUrl(url).build();uriComponents = uriComponents.encode();List queryArr = new ArrayList<>();MultiValueMap queryParams = uriComponents.getQueryParams();for (Map.Entry> next : queryParams.entrySet()) {for (String va : next.getValue()) {if (va == null) {queryArr.add(next.getKey() + "=");} else {queryArr.add(next.getKey() + "=" + va);}}}//按照字典排序Collections.sort(queryArr);///Tue, 09 Nov 2021 08:49:20 GMTDateFormat dateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));String dateTime = dateFormat.format(new Date());String signStr = method.toUpperCase() + "\n" +//拼接url pathuriComponents.getPath() + "\n" +//拼接url queryString.join("&", queryArr) + "\n" +Constants.IRS_AK + "\n" +dateTime + "\n";String sign = hmacSha256Base64(signStr, Constants.IRS_SK);IrsSignRes res = new IrsSignRes();res.setSignature(sign);res.setAccessKey(Constants.IRS_AK);res.setDateTime(dateTime);res.setAlgorithm(Constants.DEFAULT_HMAC_SIGNATURE);return res;}@SneakyThrowsprivate static String hmacSha256Base64(String content, String key) {Mac hmacSHA256 = Mac.getInstance("HmacSHA256");SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "HmacSHA256");hmacSHA256.init(secretKey);byte[] bytes = hmacSHA256.doFinal(content.getBytes(StandardCharsets.UTF_8));return Base64.getEncoder().encodeToString(bytes);}public static void main(String[] args) {System.out.println(sign("https://bcdsg.zj.gov.cn:8443/restapi/prod/IC33000020220329000007/uc/sso/getUserInfo", "POST"));}}

(3)IrsSignRes

/*** @author jie.chen* @date 2022-03-30 15:28*/
@Data
public class IrsSignRes {private String accessKey;private String signature;private String algorithm;private String dateTime;
}

(4)AuthService 业务实现类

/*** @author jie.chen* @date 2022-03-30 15:49*/
@Component
public class AuthService {@Autowiredprivate RestTemplateBuilder restTemplateBuilder;private RestTemplate restTemplate;@PostConstructvoid init() {restTemplate = restTemplateBuilder.build();}public String getTokenByTicketId(String ticketId) {HttpHeaders headers = getHttpHeaders(Constants.ACCESS_TOKEN_URL);JSONObject body = new JSONObject();body.put("appId", Constants.APP_ID);body.put("ticketId", ticketId);HttpEntity> request = new HttpEntity<>(body, headers);ResponseEntity stringResponseEntity = restTemplate.postForEntity(Constants.ACCESS_TOKEN_URL, request, String.class);return checkResponse(stringResponseEntity).getJSONObject("data").getString("accessToken");}public JSONObject getUserInfoByToken(String accessToken) {HttpHeaders headers = getHttpHeaders(Constants.GET_USER_INFO_URL);JSONObject body = new JSONObject();body.put("token", accessToken);HttpEntity> request = new HttpEntity<>(body, headers);ResponseEntity stringResponseEntity = restTemplate.postForEntity(Constants.GET_USER_INFO_URL, request, String.class);return checkResponse(stringResponseEntity).getJSONObject("data");}private JSONObject checkResponse(ResponseEntity stringResponseEntity) {if (!stringResponseEntity.getStatusCode().is2xxSuccessful()) {//请求失败throw new RuntimeException("status:" + stringResponseEntity.getStatusCodeValue() + " " + stringResponseEntity.getBody());}JSONObject result = JSON.parseObject(stringResponseEntity.getBody());if (result.containsKey("errorCode") && result.getString("errorCode") != null && !result.getBooleanValue("success")) {//业务错误throw new RuntimeException(result.toString());}return result;}private HttpHeaders getHttpHeaders(String url) {IrsSignRes res = IrsUtils.sign(url, "POST");HttpHeaders headers = new HttpHeaders();headers.add(Constants.X_BG_HMAC_ACCESS_KEY, res.getAccessKey());headers.add(Constants.X_BG_HMAC_ALGORITHM, res.getAlgorithm());headers.add(Constants.X_BG_HMAC_SIGNATURE, res.getSignature());headers.add(Constants.X_BG_DATE_TIME, res.getDateTime());return headers;}

(5)LoginController 接口测试

/*** @author hejun* @since 2022-02-22 10:46:11*/
@RestController
@RequestMapping("/user")
@Api(tags="用户登录")
@Slf4j
public class LoginController extends ProBaseController {@GetMapping(value = "zlbWxLoginTest")@ApiOperation(value = "测试浙里办微信小程序登录接口", notes = "测试浙里办微信小程序登录接口后端接口")public String zlbWxLoginTest(@RequestParam @ApiParam(name = "st", value = "浙里办 ticketId", required = true)String st) {try {return buildResultStr(buildSuccessResultData(userService.getUserBeanByTicketId(st)));}catch (Exception e) {logError(log, e);return buildResultStr(buildErrorResultData(e.getMessage()));}}
}

(6) UserServiceImpl 浙里办用户体系转换

/*** 用户表(User)表服务实现类** @author hejun* @since 2022-02-22 10:02:16*/
@Service("userService")
@Slf4j
public class UserServiceImpl implements UserService {@Autowiredprivate AuthService authService;@Overridepublic UserBean getUserBeanByTicketId(String ticketId){UserBean userBean = new UserBean();//1. 通过ticketId 换取 accessTokenString token = authService.getTokenByTicketId(ticketId);//3. 通过accessToken 获取用户信息JSONObject userInfo = authService.getUserInfoByToken(token);JSONObject personInfo = userInfo.getJSONObject("personInfo");String phone = personInfo.get("phone").toString();userBean.setMobile(phone);userBean.setUsername(personInfo.get("userName").toString());userBean.setIdnum(personInfo.get("idNo").toString());userBean.setUserid(personInfo.get("userId").toString());String login = null;if (StringUtils.isNotNullString(phone)){login = this.login(phone);userBean.setToken(login);log.info("token------------------------------", login);}return userBean;}/*** 通过手机号登录** @return token*/@Overridepublic String login(String phone) {User user = this.getUserByPhone(phone);if (user == null){user = new User();user.setMobile(phone);this.insert(user);}//生成tokenString token = getUserRsid(phone);token = token.replaceAll("/","_");//token放入缓存JedisUtils.setObject(token,user,portalRsidCacheSeconds);//返回tokenreturn token;}}

六、接口调用方式

请以POST方式提交请求参数以application/json形式提交

    1. 鉴权参数说明

“浙里办”单点登录,HTTP请求都必须在请求头(HTTP Header)中设置如下4个参数:

参数名

是否必填

类型

说明

X-BG-HMAC-SIGNATURE

string

API输入参数签名结果

X-BG-HMAC-ALGORITHM

string

签名的摘要算法,当前仅支持hmac-sha256。

X-BG-HMAC-ACCESS-KEY

string

分配给应用的accessKey,例如:12345678。

X-BG-DATE-TIME

string

时间戳,时区为GMT+8,格式为:Tue, 09 Nov 2021 08:49:20 GMT。服务端允许客户端请求最大时间误差为100秒。

其中X-BG-HMAC-SIGNATURE的计算公式为:

signature = HMAC-SHA256-HEX(secret_key,signing_string)

各字段解释如下:

  1. secret_key为接口申请完成后获取到的secret_key
  2. signing_string由请求方法、URI、请求参数等拼接获得,具体如下:

HTTP_METHOD+\n+HTTP_URI+\n+QUERY_STREAM+\n+X-BG-HMAC-ACCESS-KEY+\n+X-BG-DATE+\n

参数解释如下图,详细代码可参考签名计算代码

参数名

说明

HTTP METHOD

指 HTTP 协议中定义的 GET、PUT、POST 等请求方法,必须使用全大写的形式。

HTTP URI

请求路径,要求必须以“/”开头,不以“/”开头的需要补充上,空路径为“/”

X-BG-DATE

请求头中的 Date ( GMT 格式 )格式为:“Tue, 09 Nov 2021 08:49:20 GMT”

QUERY_STREAM

是对于 URL 中的 query( query 即 URL 中?后面的 key1=valve1&key2=valve2 字符串)进行编码后的结果。以 key 按照字典顺序( ASCII 码由小到大)排序,并使用 & 符号连接起来,生成相应的query_string。

  • 接口说明
    1. 基于单点登录票据换取请求token
    1. 请求地址

 /uc/sso/access_token

    1. 入参

参数

类型

描述

ticketId

String

单点登录票据

appId

String

AppId

    1. 出参

参数

类型

描述

errorCode

String

错误码

errorMsg

String

错误信息

success

Boolean

请求是否成功

data

Object

响应体

|- accessToken

String

获取用户信息token

    1. 错误码

错误码

描述

C-USER-SSO-TICKET-INVALID

ticket非法

    1. 基于token获取用户信息
  1. 请求地址

/uc/sso/getUserInfo

  1. 入参

参数

类型

描述

token

String

获取用户信息token

  1. 出参

参数

类型

描述

success

Boolean

请求是否成功

errorCode

String

错误码

errorMsg

String

错误信息

data

Object

响应体

|- userType

String

用户类型,PERSON

个人/LEGAL_PERSON

法人

|- personInfo

Object

个人用户信息,当前登陆自然人的信息

|-- userId

String

主键

|-- userName

String

个人姓名

|-- idType

String

ID_CARD:身份证,PASSPORT:护照,OFFICER_CARD:军官证,MAINLAND_TRAVEL_PERMIT_FOR_HONGKONG_AND_MACAO_RESIDENTS:港澳居民来往内地通行证,MAINLAND_TRAVEL_PERMIT_FOR_TAIWAN_RESIDENTS:台湾居民来往大陆通行证,FOREIGN_PERMANENT_RESIDENT_ID_CARD:外国人永久居留身份证,FOREIGN_PASSPORT:外籍人士护照,DIPLOMACY_PASSPORT:外交护照,OFFICIAL_PASSPORT:公务护照,SOLDIER_CARD:士兵证,OFFICER_RETIRE_CARD:军官离退休证,GANG_AO_TAI_RESIDENCE_CART:港澳台居民居住证,GANG_AO_ID_CART:港澳居民身份证,UNIFIED_SOCIAL_ID:统一社会信用代码,OTHER:其他

|-- outerIdType

String

外部证件类型

|-- idNo

String

证件编号

|-- attnUserType

String

法人经办人时用户类型,评级

|-- phone

String

手机号

|-- email

String

邮箱

|-- nation

String

民族

|-- gender

String

性别

|-- birthday

String

生日

|-- certKey

String

身份散列值

|-- attributes

Object

额外属性

|- legalPersonInfo

Object

法人用户信息,比如公司相关的信息

|-- name

String

法人名称

|-- unifiedSocialId

String

社会统一信用代码

|-- orgType

String

法人类型

|-- attnName

String

经办人姓名

|-- attnPhone

String

经办人手机号

|-- attnIdType

String

经办人证件类型

|-- attnIdNo

String

经办人证件号码

|-- attnUserType

String

经办人用户等级

|-- principal

String

法人代表人姓名

|-- gender

Integer

法人代表人性别

|-- nation

Integer

法人代表人民族

|-- idType

Integer

法人代表人证件类型

|-- outerIdType

String

法人代表人外部证件类型

|-- idNo

String

法人代表人证件号码

|-- principalUserId

String

法人代表唯一键

|-- corpId

String

法人唯一键

|-- attributes

Object

额外属性

|- organizationInfoList

Array

所属组织信息

|-- orgId

String

组织主键

|-- oid

String

Alias for orgId

|-- parentId

String

父组织主键

|-- pid

String

Alias for parentId

|-- name

String

组织机构简称

|--fullName

String

组织机构全称

|--devCoding

String

组织后缀

|--leafFlag

Boolean

是否叶子标志

|--orderBy

Integer

排序号,从小到大

  1. 错误码

错误码

描述

C-USER-SSO-TOKEN-INVALID

token非法

C-USER-SSO-USER-EMPTY

用户信息为空

相关内容

热门资讯

北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...