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

|
|
|
|
| atg.biz.userquery |
|
|
|
| ||
|
|
|
|
|
|
Java代码案例:
/**
* @author zyw
* @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";
}
/**
* @author zyw
* @date 2022-03-30 15:28
*/
public class IrsUtils {
@SneakyThrows
public static IrsSignRes sign(String url, String method) {
UriComponents uriComponents = UriComponentsBuilder.fromHttpUrl(url).build();
uriComponents = uriComponents.encode();
List<String> queryArr = new ArrayList<>();
MultiValueMap<String, String> queryParams = uriComponents.getQueryParams();
for (Map.Entry<String, List<String>> 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 GMT
DateFormat 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 path
uriComponents.getPath() + "\n" +
//拼接url query
String.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;
}
@SneakyThrows
private 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"));
}
}
/**
* @author zyw
* @date 2022-03-30 15:28
*/
@Data
public class IrsSignRes {
private String accessKey;
private String signature;
private String algorithm;
private String dateTime;
}
/**
* @author zyw
* @date 2022-03-30 15:49
*/
@Component
public class AuthService {
@Autowired
private RestTemplateBuilder restTemplateBuilder;
private RestTemplate restTemplate;
@PostConstruct
void 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<Map<String, Object>> request = new HttpEntity<>(body, headers);
ResponseEntity<String> 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<Map<String, Object>> request = new HttpEntity<>(body, headers);
ResponseEntity<String> stringResponseEntity = restTemplate.postForEntity(Constants.GET_USER_INFO_URL, request, String.class);
return checkResponse(stringResponseEntity).getJSONObject("data");
}
private JSONObject checkResponse(ResponseEntity<String> 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;
}
/**
* @author zyw
* @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()));
}
}
}
/**
* 用户表(User)表服务实现类
*
* @author zyw
* @since 2022-02-22 10:02:16
*/
@Service("userService")
@Slf4j
public class UserServiceImpl implements UserService {
@Autowired
private AuthService authService;
@Override
public UserBean getUserBeanByTicketId(String ticketId){
UserBean userBean = new UserBean();
//1. 通过ticketId 换取 accessToken
String 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
*/
@Override
public String login(String phone) {
User user = this.getUserByPhone(phone);
if (user == null){
user = new User();
user.setMobile(phone);
this.insert(user);
}
//生成token
String token = getUserRsid(phone);
token = token.replaceAll("/","_");
//token放入缓存
JedisUtils.setObject(token,user,portalRsidCacheSeconds);
//返回token
return token;
}
}
请以POST方式提交请求,参数以application/json形式提交。
“浙里办”单点登录,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) |
各字段解释如下:
| 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。 |
| 参数 | 类型 | 描述 |
| ticketId | String | 单点登录票据 |
| appId | String | AppId |
| 参数 | 类型 | 描述 |
| errorCode | String | 错误码 |
| errorMsg | String | 错误信息 |
| success | Boolean | 请求是否成功 |
| data | Object | 响应体 |
| |- accessToken | String | 获取用户信息token |
| 错误码 | 描述 |
| C-USER-SSO-TICKET-INVALID | ticket非法 |
| 参数 | 类型 | 描述 |
| token | String | 获取用户信息token |
| 参数 | 类型 | 描述 |
| 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 | 手机号 |
| | 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 | 排序号,从小到大 |
|
|
|
|
| 错误码 | 描述 |
| C-USER-SSO-TOKEN-INVALID | token非法 |
| C-USER-SSO-USER-EMPTY | 用户信息为空 |
前言一般来说,前端根据后台返回code码展示对应内容只需要在前台判断code值展示对应的内容即可,但要是匹配的code码比较多或者多个页面用到时,为了便于后期维护,后台就会使用字典表让前端匹配,下面我将在微信小程序中通过wxs的方法实现这个操作。为什么要使用wxs?{{method(a,b)}}可以看到,上述代码是一个调用方法传值的操作,在vue中很常见,多用于数据之间的转换,但由于微信小程序诸多限制的原因,你并不能优雅的这样操作,可能有人会说,为什么不用if判断实现呢?但是if判断的局限性在于如果存在数据量过大时,大量重复性操作和if判断会让你的代码显得异常冗余。wxswxs相当于是一个独立
项目介绍随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱小学生兴趣延时班预约小程序的设计与开发被用户普遍使用,为方便用户能够可以随时进行小学生兴趣延时班预约小程序的设计与开发的数据信息管理,特开发了小程序的设计与开发的管理系统。小学生兴趣延时班预约小程序的设计与开发的开发利用现有的成熟技术参考,以源代码为模板,分析功能调整与小学生兴趣延时班预约小程序的设计与开发的实际需求相结合,讨论了小学生兴趣延时班预约小程序的设计与开发的使用。开发环境开发说明:前端使用微信微信小程序开发工具:后端使用ssm:VU
@作者:SYFStrive @博客首页:HomePage📜:微信小程序📌:个人社区(欢迎大佬们加入)👉:社区链接🔗📌:觉得文章不错可以点点关注👉:专栏连接🔗💃:感谢支持,学累了可以先看小段由小胖给大家带来的街舞👉微信小程序(🔥)目录自定义组件-behaviors 1、什么是behaviors 2、behaviors的工作方式 3、创建behavior 4、导入并使用behavior 5、behavior中所有可用的节点 6、同名字段的覆盖和组合规则总结最后自定义组件-behaviors 1、什么是behaviorsbehaviors是小程序中,用于实现
提供3种Ubuntu系统安装微信的方法,在Ubuntu20.04上验证都ok。1.WineHQ7.0安装微信:ubuntu20.04安装最新版微信--可以支持微信最新版,但是适配的不是特别好;比如WeChartOCR.exe报错。2.原生微信安装:linux系统下的微信安装(ubuntu20.04)--微信适配的最好,反应最快,但是微信版本只到2.1.1,版本太老,很多功能都没有。3.深度deepin-wine6安装微信:ubuntu20.04+系统deepin-wine6安装新版微信--综合比较好,当前个人使用此种方法1个月,微信版本3.4;没什么大问题,尚可。一、WineHQ7.0安装微信
对传统的餐饮商家来说,小程序很好地解决了餐厅线下线上连接的问题,在引流获客、节约人力、营销宣传、塑造会员体系、改善消费体验等方面都有很大帮助。小程序点餐可以帮助餐饮企业节省一大把人力开支。一个包含扫码点单、菜品管理、优惠券推送、外卖配送的小程序,商家花几万元就能完成开发测试并投入。商家为什么要开通“扫码点餐”1.解决服务员不够用的问题。2.不怕顾客跑单漏单。3.在微信就能管理菜品、查看营业额。4.订单小票显示顾客桌号和已点菜品。5.可在“附近的小程序”找到您的门店。如今餐饮业常用的三种经营模式:1堂食点单模式客人通过小程序堂食点单。商家可以在微信扫码点餐小程序管理后台根据自己店内情况来设置不同
技术选型1,前端小程序原生MINA框架cssJavaScriptWxml2,管理后台云开发Cms内容管理系统web网页3,数据后台小程序云开发云函数云开发数据库(基于MongoDB)云存储4,人脸识别算法基于百度智能云实现人脸识别一,用户端效果图预览老规矩我们先来看效果图,如果效果图符合你的需求,就继续往下看,如果不符合你的需求,可以跳过。1-1,登录注册页可以看到登录页有注册入口,注册页如下我们的注册,需要管理员审核,审核通过后才可以正常登录使用小程序1-2,个人中心页登录成功以后,我们会进入个人中心页我们在个人中心页可以注册人脸,因为我们做人脸识别签到,需要先注册人脸才可以进行人脸比对,进
在开发微信小程序的时候,我们可能需要开发环境和测试环境,或者其他环境,下面是切换环境的方法。首先需要明确的是:前端的页面代码是不区分环境的,环境的区分指的是云函数、云数据库、云存储这些。1、更改云函数的使用云环境这里我们从cloud1更改为test-cloud,这个改完是没有用的,因为在前端代码指定了使用的云环境。cloudfunctions文件和miniprogram文件虽然都在一个目录下,但是这两个没有直接联系。2、在evList.js中添加自己云环境evList.js存储了云环境列表,这里把test-cloud加到这个列表里,需要填写envId和alias,参照cloud1写就行。3、更
前言微信支付是企业级项目中经常使用到的功能,作为后端开发人员,完整地掌握该技术是十分有必要的。一、申请流程和步骤图1-1注册微信支付账号获取微信小程序APPID获取微信商家的商户ID获取微信商家的API私钥配置微信支付回调地址绑定微信小程序和微信支付的关系搭建SpringBoot工程编写后台支付接口发布部署接口服务项目使用微信小程序或者UniAPP调用微信支付功能支付接口的封装配置jwt或者openid的token派发原生微信小程序完成支付对接二、注册商家2.1商户平台商家或者企业想要通过微信支付来进行商品的销售,必须先通过微信平台(pay.weixin.qq.com)去将商家进行注册。注册成
介绍 最近在做微信小程序时,顶部标题栏总是与胶囊对不齐。往往是在这款手机上对齐了,在另外一款手机差很多。我在查阅资料后,提出了一种方法解决这个问题,即:在页面onLoad或组件created时,利用微信小程序提供的API,获取系统状态栏高度和胶囊信息,进而动态调整顶部标题栏样式。在苹果、小米、荣耀手机做验证,能做到精准对齐。理论 胶囊样式应该是垂直居中,有1px的border,border-radius为18px。 若要使顶部标题栏与胶囊对齐,则其高度必须是导航栏高度,标题栏内容也要垂直居中,顶部标题栏的外边距或内边距必须是状态栏高度。 如果顶部
项目背景和意义 目的:本课题主要目标是设计并能够实现一个基于微信校园跑腿小程序系统,前台用户使用小程序发布跑腿任何和接跑腿任务,后台管理使用基于PHP+MySql的B/S架构;通过后台管理跑腿的用户、查看跑腿信息和对应订单。意义:手机网络时代,大学生通过手机网购日常用品、外卖外卖、代取快递等已不再是稀奇的事情。此外,不少高校还流行着校园有偿工作,校园跑腿就成了大学生创业服务项目。 因为你在校园里,所以不会有进入的限制。并不是所有的外卖平台都可以随意进入校园,比如小黄和小蓝的双打外卖平台。许多大学禁止送餐进入学校,更不用说送餐进入宿舍了。这一措施使得校园服务市场的竞争相对不