微信小程序备案设计

     

目录

1 小程序负责人的人脸核身

2  备案素材上传

3 备案信息填写

4 API安全 


    微信小程序是当下比较流行的小程序,也是各大网民首选的应用程序,相对于APP小程序不用安装占用较大的内存,体积小、运行速度快,小程序的流行成为各大互联网大厂兵家必争之地,互联网大厂都在推出自己的小程序生态,但做得最好的还是要数微信小程序了。

当前微信官网已发布公告:

1、已上架的小程序,须于2024年3月31日完成备案,逾期未完成备案,平台将按照备案相关规定于2024年4月1日起进行清退处理。

2、若微信小程序未上架,自2023年9月1日起,微信小程序须完成备案后才可上架。

本平台已完成小程序的备案功能。 已入驻本平台的小程序将由平台工作人员协助商户完成小程序的备案工作。也就是说,微信小程序不通过备案是无法上架的。

笔者从自己的研发团队实战经验出发从技术上来讲解一下第三方平台小程序的备案过程。(注:第三方平台小程序是代商户托管、维护小程序并代为开发的平台方,商家授权平台方去管理小程序,将精力集中在业务上,小程序的开发、代码上传、提交审核、发布、备案等由平台方完成,还省去了每年300元的认证费用,你说爽不爽? 为微信这个点赞! )

小程序的备案分为: 小程序负责人的人脸核身、备案素材上传、备案信息填写三大步骤 。

 现在直接进入主题吧:进入小程序备案页:

1 小程序负责人的人脸核身

以上是人脸核身请求已通过的记录。

如果人脸核身如果不通过,界面如下:

点击 “向商家发起人脸核身任务”后,平台就代商家小程序提交一个人脸核身的请求。 

 接口层: 

@RequestMapping(value = {"/security_superadmin/mini/icp/task/create"}, method = RequestMethod.POST)
    public Mono<JSONObject> createIcp(@RequestBody JSONObject body) throws Throwable {
            return wechatPlatformService.createIcp(body);

    }

服务层:

public Mono<JSONObject> createIcp(JSONObject body) throws Exception {

        String component_appid = body.getString("component_appid");
        String authorizer_appid = body.getString("authorizer_appid");
        MiniFaceSet set = miniFaceSetRepository.getMiniFaceSet(component_appid,authorizer_appid);
        if (set != null &&  3 != set.getStatus().intValue() ) {
            throw new Exception("已有申请记录,不可重复提交");
        }

        PlatformGrant grant = getApiToken(component_appid, authorizer_appid);
        String url = "https://api.weixin.qq.com/wxa/icp/create_icp_verifytask?access_token=" + grant.getAuthorizer_access_token();
        body.remove("component_appid");
        body.remove("authorizer_appid");
        JSONObject json = doPost(url,body);
        log.info("---->创建人脸核身请求返回 res {}", json);
        Integer status = json.getInteger("errcode");

        if (status != null && status.intValue() == 0) {
            String task_id = json.getString("task_id");
            if (set != null) {

            }else{
                set = new MiniFaceSet();
            }
            set.setTask_id(task_id);
            set.setComponent_appid(component_appid);
            set.setAuthorizer_appid(authorizer_appid);
            set.setAuthorizer_appname(grant.getMuch_mini_name());
            set.setSubmit_time(new Date());
            set.setStatus(1);
            set.setReject_reason("");
            miniFaceSetRepository.save(set);
            return Mono.just(Response.success("successs"));

        } else {

            return Mono.just(Response.error(json.getString("errmsg")));

        }

    }

MiniFacetTask 对象对应人脸核身任务记录。 提交请求后,生成一个task_id 小程序负责人微信收到一个通知,点击做一个人脸认证完成。

2  备案素材上传

 微信的备案中所涉及的证件资料是以素材ID的形式提交的,先将需要的证件资料上传生成素材。用一张表记录下来。

创建素材将接口所需要的字段动态加载出来。如下:

列表中:素材ID是上传成功微信返回的media_id ,证件类型和备案字段也要按小程序的API文档来获取接口。

3 备案信息填写

 这块内容最多,也是最复杂的,鉴于篇幅有限, 简单介绍一下。

先是备案状态查询,调用小程序状态查询接口,如果备案未通过,设计如下:

点击“代小程序发起备案”,进入备案资料的填写界面。

用一个步骤条来将复杂的过程分为三步。最后就是一个大的JSON提交给微信。

 接口层:

@RequestMapping(value = {"/security_superadmin/mini/icp/submit"}, method = RequestMethod.POST)
    public Mono<JSONObject> icpSubmit(@RequestBody JSONObject body) throws Throwable
    {

        return  wechatPlatformService.submitIcp(body);

    }

服务层:

public Mono<JSONObject> submitIcp(JSONObject body) throws Exception {

        log.info("--->备案请求 {}", body);
        String component_appid = body.getString("component_appid");
        String authorizer_appid = body.getString("authorizer_appid");

        PlatformGrant grant = getApiToken(component_appid, authorizer_appid);
        String url = "https://api.weixin.qq.com/wxa/icp/apply_icp_filing?access_token=" + grant.getAuthorizer_access_token();
        JSONArray other_materials = body.getJSONArray("other_materials");
        log.info("---->other_materials {}", other_materials);
        Collection<String> media_ids = new HashSet<>();
        if (other_materials != null &&  0 < other_materials.size()) {
              for ( int i = 0 ; i < other_materials.size() ; i++ ) {
                  media_ids.add(other_materials.getString(i));
              }
        }
        JSONObject icp_materials = body.getJSONObject("icp_materials");
        Assert.notNull(icp_materials, "icp_materials字段缺失");
        body.remove("component_appid");
        body.remove("authorizer_appid");
        body.remove("other_materials");

        if (media_ids.size() > 0) {
               List<MiniMediaRecord> medias =  miniMediaRecordRepository.getRecords(component_appid,authorizer_appid, media_ids);
               if(!CollectionUtils.isEmpty(medias)) {
                  Map<String,Set<String>> map = new HashMap<>(); // key ,  icp_order_field.split("\\.")[1], value: Set<String>
                  for( MiniMediaRecord media: medias ) {
                        String icp_order_field = media.getIcp_order_field().split("\\.")[1];
                        log.info("--->key icp_order_field {}", icp_order_field);
                        Set<String>  list  = map.get(icp_order_field);
                        if ( list == null) {
                            list = new HashSet<>();
                        }
                        list.add(media.getMedia_id());
                        map.put(icp_order_field, list);
                   }

                   for (Map.Entry<String,Set<String>> entry: map.entrySet()) {

                       icp_materials.put(entry.getKey(), entry.getValue());
                   }
                   body.put("icp_materials",icp_materials);
                   log.info("----> 向微信提交的 JSON {}", body.toJSONString());
              }
        }

        log.info("---> body {}",body.toJSONString());
        JSONObject json = doPost(url,body);
        log.info("---->提交备案结果返回 res {}", json);
        Integer status = json.getInteger("errcode");
        String errmsg = json.getString("errmsg");
        if (status != null && status.intValue() == 0) {

              return Mono.just(Response.success("success"));

        }else{

            return Mono.just(Response.error(errmsg));
        }

    }

4 API安全 

注意:接口以  /security_superadm/** 开头的请求需要有超管角色才可发起。在网关层对所有入网请求进行统一过滤:

@Bean
	public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
		SecurityWebFilterChain chain =
				http.cors().and().csrf().disable()
							.authenticationManager(mySecurityAuthenManager)
							.securityContextRepository(securityContextRepository).addFilterBefore(new GatewayFilter(aesUtil, jwtUtils),SecurityWebFiltersOrder.CORS)
							.authorizeExchange()
						
					    							.pathMatchers("/security_superadmin/**").hasAnyAuthority("SUPER_ADMIN")
							
	                .and().exceptionHandling().authenticationEntryPoint(new UnauthenEntrypoint())  //未登录访问资源时的处理类,若无此处理类,前端页面会弹出登录
							.accessDeniedHandler(new ServerAccessDeniedHandler() {
								@Override
								public Mono<Void> handle(ServerWebExchange serverWebExchange, AccessDeniedException e) {

									JSONObject res = new JSONObject();
									res.fluentPut("resCode", "403").fluentPut("resMsg", "敏感资源拒绝访问");
									ServerHttpResponse response = serverWebExchange.getResponse();
									response.getHeaders().set(HttpHeaders.CONTENT_TYPE, "application/json; charset=UTF-8");

									String result = JSONObject.toJSONString(res);
									DataBuffer buffer = response.bufferFactory().wrap(result.getBytes(CharsetUtil.UTF_8));
									return response.writeWith(Mono.just(buffer));

								}
							})
                    .and().build();

	     
	          return chain;
	   }
	  

 小程序备案仅仅只是小程序平台的其中一个小功能而已。春节前时逢微信小程序备案,想必各互联网企业和开发者都要为止伤脑筋了,希望本文能够给大家赋能。

详细的设计可以参考这篇文章:

微信第三方小程序平台端-小程序备案功能上线

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值