【公众号】微信进入公众号链接自动获取授权登陆

article/2025/10/1 18:44:16

文章目录

  • 前言
  • 一、准备
  • 二、开发
    • 2.1 搭建项目
    • 2.2 WeixinUtil 工具
    • 2.3 回调接口与登陆接口
    • 2.4 过滤器自动登陆
    • 2.4 其他类
    • 2.5 测试
  • 三、总结

前言

最近项目上有一个需求,用户反映每次从微信打开链接都需要手动登陆,比较繁琐,想点开微信连接后自动登陆,加快审批操作。接到这个需求一开始想的是平时在刷微信公众号的时候,进一些第三方应用网页会要求授权,之后就不需要登陆了。顺着这个思路,在网上百度了一下,了解到微信网页开发中的一个网页授权。经过一系列测试发现是可用的,特此记录。本文仅限测试公众号,后续企业公众号项目上线再来回顾。

  • 本文采用的是绑定openid 到 系统中的用户,因此登陆和授权二者都要通过,绑定之后便可以自动登陆。

一、准备

  • 1.需要一个测试公众号
    申请了个人公众号之后,在左侧菜单栏中,进入开发者工具 》选择公众号测试帐号

在这里插入图片描述
我们需要的是APPIDappsecret

然后往下滑动,到网页服务栏中,设置网页帐号

在这里插入图片描述
单击后面的修改,配置回调的域名,测试账号是支持设置ip的,如果是在本地开发,我们可以设置为127.0.0.1,注意不需要添加http之类的。域名则只用填写域名。

  • 2.微信web开发者调试工具
    这个只用去官网下载即可;这个工具可以在开发时,模拟手机微信访问链接,进行授权。

二、开发

2.1 搭建项目

项目结构SpringBoot + Mybatis + Themeleaf

  • 1.pom依赖
   <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.5.RELEASE</version></parent><dependencies><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><!--<version>8.0.11</version>--><version>5.1.47</version></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>1.3.2</version></dependency><dependency><groupId>commons-net</groupId><artifactId>commons-net</artifactId><version>3.1</version></dependency><dependency><groupId>net.sf.json-lib</groupId><artifactId>json-lib</artifactId><version>2.2.3</version><classifier>jdk15</classifier><!-- jdk版本 --></dependency><dependency><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.2.1</version></dependency><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpcore</artifactId><version>4.2.1</version></dependency><dependency><groupId>commons-lang</groupId><artifactId>commons-lang</artifactId><version>2.6</version></dependency><!-- 引入thymeleaf模板引擎--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency></dependencies><build><resources><resource><directory>src/main/java</directory><!--java文件的路径--><includes><include>**/*.*</include></includes><!-- <filtering>false</filtering>--></resource><resource><directory>src/main/resources</directory><!--资源文件的路径--><includes><include>**/*.*</include></includes><!-- <filtering>false</filtering>--></resource></resources></build>
  • 2.启动类
@SpringBootApplication
@MapperScan("com.dao")
@ServletComponentScan("com.filter")
public class App_80 {public static void main(String[] args) {SpringApplication.run(App_80.class);}}
  • 3.配置文件application.yml
server:port: 80  #80端口是因为回调地址如果带端口是报错,80端口可以直接用127.0.0.1访问logging:level:com.dao: DEBUGmybatis:mapper-locations: classpath:mapper/**/*.xmlspring:datasource:url: jdbc:mysql://localhost:3306/db_ads?serverTimezone=UTC&useSSL=falsedriver-class-name: com.mysql.jdbc.Driverusername: rootpassword: xxhikari:minimum-idle: 3maximum-pool-size: 10max-lifetime: 30000connection-test-query: SELECT 1thymeleaf:
#    prefix: classpath:/templates
#    suffix: .htmlencoding: utf-8check-template: truecache: false

3.其他包括登陆用户实体类,mapper文件,service等;由于篇幅限制,部分类均最后贴上

2.2 WeixinUtil 工具

这个类基本上用来和微信api交互,所以我们封装成一个util

public class WeixinUtil {static Logger log = LoggerFactory.getLogger(WeixinUtil.class);//则scope为snsapi_base不会跳页面 snsapi_userinfo 会弹出页面private static String auth_url  = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=[appid]&redirect_uri=[projectUrl]/getOpenInfo/[redirectUrl]&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect";//其他urlpublic final static String getOpen_id_url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";public final static String getNewAccess_token = "https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=APPID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN";//公众号的配置public static String appid = "wx5eb3c26d6d692516";public static String appsecret = "00b5715e2542ec74a2dac31b12cfae4a";public static String websiteAndProject = "http://121.43.230.40"; //项目地址//回调地址记录,可能部分地址带有参数,避免参数不识别等问题private static volatile Map<String,String>  urlMap = new ConcurrentHashMap<>();/*** 将需要访问的地址置入map中,以md5作为key* @param url* @return* @throws Exception*/public static String setUrl(String url) throws Exception {if(StringUtils.isEmpty(url)){ throw new Exception("访问地址为空"); }String md5Key = DigestUtils.md5DigestAsHex(url.getBytes());urlMap.put(md5Key,url);return md5Key;}/*** 根据md5获取访问的全路径* @param key* @return* @throws Exception*/public static String getUrl(String key) throws Exception {if(StringUtils.isEmpty(key)){ throw new Exception("key为空"); }String url = urlMap.get(key);return websiteAndProject + url;}/*** 获取授权地址,拼接* @param urlCode 回调地址的md5key* @return*/public static String getAuthUrl(String urlCode){return auth_url.replace("[appid]",appid).replace("[projectUrl]",websiteAndProject).replace("[redirectUrl]",urlCode);}/*** 发起https请求并获取结果* @param requestUrl 请求地址* @param requestMethod 请求方式(GET、POST)* @param outputStr 提交的数据* @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值)*/public static JSONObject httpRequest(String requestUrl, String requestMethod, String outputStr) {JSONObject jsonObject = null;StringBuffer buffer = new StringBuffer();try {// 创建SSLContext对象,并使用我们指定的信任管理器初始化TrustManager[] tm = { new MyX509TrustManager() };SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");sslContext.init(null, tm, new java.security.SecureRandom());// 从上述SSLContext对象中得到SSLSocketFactory对象SSLSocketFactory ssf = sslContext.getSocketFactory();URL url = new URL(requestUrl);HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();httpUrlConn.setSSLSocketFactory(ssf);httpUrlConn.setDoOutput(true);httpUrlConn.setDoInput(true);httpUrlConn.setUseCaches(false);// 设置请求方式(GET/POST)httpUrlConn.setRequestMethod(requestMethod);if ("GET".equalsIgnoreCase(requestMethod))httpUrlConn.connect();// 当有数据需要提交时if (null != outputStr) {OutputStream outputStream = httpUrlConn.getOutputStream();// 注意编码格式,防止中文乱码outputStream.write(outputStr.getBytes("UTF-8"));outputStream.close();}// 将返回的输入流转换成字符串InputStream inputStream = httpUrlConn.getInputStream();InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");BufferedReader bufferedReader = new BufferedReader(inputStreamReader);String str = null;while ((str = bufferedReader.readLine()) != null) {buffer.append(str);}bufferedReader.close();inputStreamReader.close();// 释放资源inputStream.close();inputStream = null;httpUrlConn.disconnect();jsonObject = JSONObject.fromObject(buffer.toString());} catch (ConnectException ce) {log.error("Weixin server connection timed out.");} catch (Exception e) {log.error("https request error:{}", e);}return jsonObject;}/*** 获得用户基本信息* @param request* @param code* @param appid* @param appsecret* @return*/public static OpenIdResult getOpenId(HttpServletRequest request, String code, String appid, String appsecret) {String requestURI = request.getRequestURI();String param = request.getQueryString();if(param!=null){requestURI = requestURI+"?"+param;}String url = getOpen_id_url.replace("APPID",appid).replace("SECRET",appsecret).replace("CODE",code);JSONObject jsonObject = httpRequest(url, "POST", null);OpenIdResult result = new OpenIdResult();if (null != jsonObject) {Object obj = jsonObject.get("errcode");if (obj == null) {result.setAccess_token(jsonObject.getString("access_token"));result.setExpires_in(jsonObject.getString("expires_in"));result.setOpenid(jsonObject.getString("openid"));result.setRefresh_token(jsonObject.getString("refresh_token"));result.setScope(jsonObject.getString("scope"));}else{System.out.println("获取openId回执:"+jsonObject.toString()+"访问路径:"+requestURI);log.error("访问路径:"+requestURI);log.error("获取openId失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg"));}}return result;}/*** 检验授权凭证(access_token)是否有效* @param accessToken 凭证* @param openid id* @return*/public static int checkAccessToken(String accessToken, String openid) {String requestUrl = "https://api.weixin.qq.com/sns/auth?access_token="+accessToken+"&openid="+openid;JSONObject jsonObject = httpRequest(requestUrl, "GET", null);int result = 1;// 如果请求成功if (null != jsonObject) {try {result = jsonObject.getInt("errcode");} catch (JSONException e) {accessToken = null;// 获取token失败log.error("获取token失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg"));}}return result;}/*** 用户授权,使用refresh_token刷新access_token* @return*/public static OpenIdResult getNewAccess_Token(OpenIdResult open,String refresh_token,String openId) {String requestUrl = getNewAccess_token.replace("REFRESH_TOKEN", refresh_token).replace("APPID", openId);JSONObject jsonObject = httpRequest(requestUrl, "GET", null);// 如果请求成功if (null != jsonObject) {try {open.setAccess_token(jsonObject.getString("access_token"));} catch (JSONException e) {// 获取token失败log.error("获取token失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg"));}}return open;}/*** 通过网页授权获取用户信息* @param accessToken 网页授权接口调用凭证* @param openId 用户标识* @return WeixinUserInfo*/public static WeixinUserInfo getWeixinUserInfo(String accessToken, String openId) {WeixinUserInfo user = null;// 拼接请求地址String requestUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID";requestUrl = requestUrl.replace("ACCESS_TOKEN", accessToken).replace("OPENID", openId);// 通过网页授权获取用户信息JSONObject jsonObject = httpRequest(requestUrl, "GET", null);if (null != jsonObject) {try {user = new WeixinUserInfo();// 用户的标识user.setOpenId(jsonObject.getString("openid"));// 昵称user.setNickname(jsonObject.getString("nickname"));// 性别(1是男性,2是女性,0是未知)user.setSex(jsonObject.getInt("sex"));// 用户所在国家user.setCountry(jsonObject.getString("country"));// 用户所在省份user.setProvince(jsonObject.getString("province"));// 用户所在城市user.setCity(jsonObject.getString("city"));// 用户头像user.setHeadImgUrl(jsonObject.getString("headimgurl"));// 用户特权信息user.setPrivilegeList(JSONArray.toList(jsonObject.getJSONArray("privilege"), List.class));} catch (Exception e) {user = null;int errorCode = jsonObject.getInt("errcode");String errorMsg = jsonObject.getString("errmsg");log.error("获取用户信息失败 errcode:{} errmsg:{},reqUrl{}", errorCode, errorMsg);}}return user;}
}

2.3 回调接口与登陆接口

回调接口是指,获取授权成功之后微信需要调用该接口传递code等数据,因此需要写一个controller来接收微信的回调。该接口的mapping也是对应获取授权地址中的redirect_uri参数。
如本项目中,定义为&redirect_uri=[projectUrl]/getOpenInfo/[redirectUrl]&因此我们的mapping就是getOpenInfo/{redirectUr}

@Controller
public class WxController {Logger log = LoggerFactory.getLogger(WxController.class);@AutowiredUserService userService;/*** 微信网页授权获得微信详情* @param code* @param state* @param redirect 授权后跳转的视图 md5 key* @param request* @param response* @throws ServletException* @throws IOException*/@RequestMapping("/getOpenInfo/{redirect}")public void getOpenInfo(Model model, @RequestParam("code") String code, @RequestParam("state") String state, @PathVariable("redirect") String redirect, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {log.error("授权成功回调");HttpSession session = request.getSession();User user = (User)session.getAttribute("C_USER");// 用户同意授权if (!"authdeny".equals(code)) {//获取OpenIdOpenIdResult open = WeixinUtil.getOpenId(request, code, WeixinUtil.appid, WeixinUtil.appsecret);//检验授权凭证(access_token)是否有效,如果需要微信的用户信息,可以去掉这些注释/*     int result = WeixinUtil.checkAccessToken(open.getAccess_token(), open.getOpenid());if(0 != result){open = WeixinUtil.getNewAccess_Token(open,open.getRefresh_token(),TimedTask.appid);}*/// 网页授权接口访问凭证// String accessToken = open.getAccess_token();String openId = open.getOpenid();//获取微信用户详细信息,如果你不需要授权,可跳过该步骤,直接以微信的OpenId,查找是否已经绑定,没有跳转到绑定界面//WeixinUserInfo wxUser = WeixinUtil.getWeixinUserInfo(accessToken, openId);//从数据库获取当前微信绑定的用户User customer = userService.getUserByOpenId(open.getOpenid());log.error("数据库的用户" + customer);if(customer!=null){//当前用户已经绑定了if(customer.getStatus()==2){ //用户不可用response.sendRedirect("/error/用户不可用");return ;}else {session.setAttribute("C_USER",customer);}//customer.setHeadPhoto(user.getHeadImgUrl());}else{log.error("未绑定用户");//未绑定用户,判断是否登陆,如果未登陆还要登陆if(user == null){//未登陆前往登陆response.sendRedirect("/toLogin/"+redirect);return ;}else{user.setOpenId(openId);//绑定userService.updateUser(user);session.setAttribute("C_USER",user);}}session.setAttribute("C_OPENID", open);response.setContentType("text/html; charset=UTF-8");try {response.sendRedirect(WeixinUtil.getUrl(redirect));} catch (Exception e) {e.printStackTrace();}return ;}else{response.setContentType("text/html; charset=UTF-8");try {response.sendRedirect("/error/"+"取消授权");} catch (IOException e) {e.printStackTrace();}return ;}}

登陆处理

@Controller
public class LoginController {@AutowiredUserService userService;/*** 登陆或者注册* @param userName* @param passWord* @param model* @return*/@PostMapping("/login")public void login(HttpServletRequest request, HttpServletResponse response,String userName, String passWord, Model model, String redirect) throws IOException, ServletException {HttpSession session = request.getSession();User user = new User().setUserName(userName).setPassWord(passWord);try{User newUser = userService.loginOrRegister(user);model.addAttribute("user",newUser);session.setAttribute("C_USER",newUser);if(StringUtils.isBlank(redirect)){redirect = "home";}session.removeAttribute("login_msg");response.sendRedirect(WeixinUtil.getUrl(redirect));}catch (Exception e){e.printStackTrace();// model.addAttribute("msg",e.getMessage());//request.getRequestDispatcher("/toLogin/" + redirect).forward(request,response);session.setAttribute("login_msg",e.getMessage());response.sendRedirect("/toLogin/"+redirect);return;}}@RequestMapping("/logout")public void logout(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {HttpSession session = request.getSession();session.invalidate();response.sendRedirect("/");}}
  • 页面跳转
@Controller
public class PageController {/*** 首页* @param model* @return*/@GetMapping("home")public String toHome(Model model){model.addAttribute("code",200);model.addAttribute("msg","hello world");return "home";}/*** 登陆页面* @param model* @return*/@GetMapping("toLogin/{redirect}")public String toLogin(Model model, @PathVariable String redirect){model.addAttribute("redirect",redirect);return "login";}/*** 登陆页面* @param model* @return*/@RequestMapping("toLogin/")public String toLoginWitOutRedict(Model model){return "login";}/*** 错误页面* @param model* @return*/@RequestMapping("error/{msg}")public String toError(Model model, @PathVariable String msg){model.addAttribute("msg",msg);return "unerror";}
}

2.4 过滤器自动登陆

我们可以对需要登陆的地方添加过滤器从而进行自动登陆或者是权限管理。

/*** 微信过滤器* 自动获取授权*/
@WebFilter(value = "/user/*")
public class WxFilter implements Filter {Logger log = LoggerFactory.getLogger(WxFilter.class);@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {HttpServletRequest httpRequest = (HttpServletRequest) request;HttpServletResponse hsResponse = (HttpServletResponse) response;String requestURI = httpRequest.getRequestURI();HttpSession session = httpRequest.getSession();//获取登陆用户标记User user = (User) session.getAttribute("C_USER");//获取授权标记OpenIdResult result = (OpenIdResult) session.getAttribute("C_OPENID");//不是手机端判断是否登陆try {if (!JudgeIsMoblie(httpRequest)) {if (user == null) {String urlKey = WeixinUtil.setUrl(requestURI);//跳到登陆页面httpRequest.getRequestDispatcher("/toLogin/" + urlKey).forward(request, response);return;}filterChain.doFilter(request, response);return;}//已经授权过 放行 未授权还要获取授权if (result != null) {//自动登陆if (user == null) {User customer = new UserService().getUserByOpenId(result.getOpenid());if (customer != null) {session.setAttribute("C_USER", customer);} else {String urlKey = WeixinUtil.setUrl(requestURI);//跳到登陆页面httpRequest.getRequestDispatcher("/toLogin/" + urlKey).forward(request, response);return;}}filterChain.doFilter(request, response);return;}//获取访问地址if (requestURI.contains("getOpenInfo")) {//认证地址 放行filterChain.doFilter(request, response);return;}log.error("微信未授权");//调用微信授权,记录回调urlString urlCode = WeixinUtil.setUrl(requestURI);hsResponse.sendRedirect(WeixinUtil.getAuthUrl(urlCode));} catch (Exception e) {e.printStackTrace();hsResponse.sendRedirect("/error/" + e.getMessage());}}//判断是否为手机浏览器public boolean JudgeIsMoblie(HttpServletRequest request) {boolean isMoblie = false;String[] mobileAgents = {"iphone", "android", "ipad", "phone", "mobile", "wap", "netfront", "java", "opera mobi","opera mini", "ucweb", "windows ce", "symbian", "series", "webos", "sony", "blackberry", "dopod","nokia", "samsung", "palmsource", "xda", "pieplus", "meizu", "midp", "cldc", "motorola", "foma","docomo", "up.browser", "up.link", "blazer", "helio", "hosin", "huawei", "novarra", "coolpad", "webos","techfaith", "palmsource", "alcatel", "amoi", "ktouch", "nexian", "ericsson", "philips", "sagem","wellcom", "bunjalloo", "maui", "smartphone", "iemobile", "spice", "bird", "zte-", "longcos","pantech", "gionee", "portalmmm", "jig browser", "hiptop", "benq", "haier", "^lct", "320x320","240x320", "176x220", "w3c ", "acs-", "alav", "alca", "amoi", "audi", "avan", "benq", "bird", "blac","blaz", "brew", "cell", "cldc", "cmd-", "dang", "doco", "eric", "hipt", "inno", "ipaq", "java", "jigs","kddi", "keji", "leno", "lg-c", "lg-d", "lg-g", "lge-", "maui", "maxo", "midp", "mits", "mmef", "mobi","mot-", "moto", "mwbp", "nec-", "newt", "noki", "oper", "palm", "pana", "pant", "phil", "play", "port","prox", "qwap", "sage", "sams", "sany", "sch-", "sec-", "send", "seri", "sgh-", "shar", "sie-", "siem","smal", "smar", "sony", "sph-", "symb", "t-mo", "teli", "tim-", "tosh", "tsm-", "upg1", "upsi", "vk-v","voda", "wap-", "wapa", "wapi", "wapp", "wapr", "webc", "winw", "winw", "xda", "xda-","Googlebot-Mobile"};if (request.getHeader("User-Agent") != null) {String agent = request.getHeader("User-Agent");for (String mobileAgent : mobileAgents) {if (agent.toLowerCase().indexOf(mobileAgent) >= 0 && agent.toLowerCase().indexOf("windows nt") <= 0 && agent.toLowerCase().indexOf("macintosh") <= 0) {isMoblie = true;break;}}}return isMoblie;}}

2.4 其他类

  • 微信用户
@Data
public class WeixinUserInfo {private String openId;private String nickname;private Integer sex;private String country;private String province;private String city;private String headImgUrl;private List privilegeList;
}
  • OpenIdResult
@Data
public class OpenIdResult {private String access_token;private String expires_in; private String refresh_token; private String openid; //用户唯一标识,请注意,在未关注公众号时,用户访问公众号的网页,也会产生一个用户和公众号唯一的OpenIDprivate String scope; //用户授权的作用域,使用逗号(,)分隔 
}
  • MyX509TrustManager
public class MyX509TrustManager implements X509TrustManager {public void checkClientTrusted(X509Certificate[] chain, String authType)throws CertificateException{}public void checkServerTrusted(X509Certificate[] chain, String authType)throws CertificateException{}public X509Certificate[] getAcceptedIssuers(){return null;}
}

还有一些mapper和servie,页面以及sql均放github(文末地址)上了。需要自取

2.5 测试

如果需要手机端也可以访问,则需要部署在服务器上,同时也要修改项目路径和回调地址。由于本次是测试项目,则写在代码中,如若正式开发,还是写在配置文件中比较好。

在这里插入图片描述

首次访问该项目,首页无账号信息。

在这里插入图片描述
进入需要权限的地址,由于未登陆且当前未绑定,因此需要登陆
在这里插入图片描述

登陆成功之后,后台会自动绑定,我们也可以看到当前登陆用户的信息,然后点击退出,清除session信息。
在这里插入图片描述
重新打开该页面,可以发现首页已经有账号信息了,且进入权限页面也不需要登陆。

三、总结

整体流程如下,由于不好处理授权与登陆先后的关系,因此回调重定向的页面都会有点多。有更好方案的欢迎评论区讨论。后续可以对接项目主动推送链接给用户以及菜单栏等操作。

在这里插入图片描述

体验链接:http://121.43.230.40 (有效期2020-10-12,阿里云学生服务器,未配置域名,电脑访问无效果)
需关注测试公众号才可获取授权:

在这里插入图片描述

GitHub项目地址:https://github.com/LiCQing/WeiXinWebAuthDemo

CSDN资源:

2020-5月的尾巴


http://chatgpt.dhexx.cn/article/rDZoKGws.shtml

相关文章

java向微信公众号---发送模板和图文消息

微信公众号初次开发 其他操作 项目搭建mavenapplication.ymlyml参数配置微信客户端配置 搭建完成 实现业务模板消息推送准备工作模板消息填写要求图文消息填写要求 推送模板消息推送模板消息结果——效果 推送图文消息推送图文消息工具类问题和结果 获取关注的用户openId既然有…

微信公众号接入天行机器人案例和方法

首先使用的是天行机器人&#xff1a; 1、接入基本原理&#xff1a; https://www.tianapi.com/apiview/47 申请完成后的结果如下 调用对应的接口的参数如下&#xff1a; http://api.tianapi.com/txapi/robot/index?keyae5e9a72c8d4cb1f5e096f7bb4daf1f3&questionrobot…

微信公众号的端口映射及服务开发

一. 开发准备 微信公众号申请---->实名认证---->服务器开发---->绑定服务器 PS: 这里有一点需要注意的就是, 微信开发必须是80端口或者443端口, 如果我们有云服务器主机一切都好办. 但是如果没有我们还有几个备选方案: 1. 花生壳 , net123 : 这两个都需要实名认证(…

[JAVA实现]微信公众号网页授权登录,java开发面试笔试题

我总结出了很多互联网公司的面试题及答案,并整理成了文档,以及各种学习的进阶学习资料,免费分享给大家。 扫描二维码或搜索下图红色VX号,加VX好友,拉你进【程序员面试学习交流群】免费领取。也欢迎各位一起在群里探讨技术。 推荐文章:Java 面试知识点解析;Mysql优化技巧…

后端操作微信公众号

一、功能说明 员工端使用微信公众号完成审批操作&#xff0c;涉及到的功能包含&#xff1a;自定义菜单、授权登录、消息 1、微信公众号一级菜单为&#xff1a;审批列表、审批中心、我的 2、员工关注公众号&#xff0c;员工第一次登录微信公众号&#xff0c;通过微信授权登录进行…

Java基于微信公众号接口实现授权登录源码及原理分析

微信公众号授权登录操作前提必须注册微信公众平台账号&#xff0c;注意的是订阅号不支持授权登录操作&#xff0c;因此对于个人开发者注册的订阅号是无法实现的&#xff0c;必须注册企业号的微信平台账号而具体注册流程就不详细介绍了&#xff0c;有什么疑问可去微信公众号平台…

微信公众号多域名回调系统1.0发布

这是一款基于ThinkPHP6.0框架的微信公众号多域名回调系统。 微信公众号后台默认只能授权2个网页域名&#xff0c;用本系统可突破这个限制&#xff0c;用同一个公众号对接无限多个网站。网站后台支持回调域名白名单的管理&#xff0c;以及登录记录的查看。 本系统还有微信access…

PHP微信扫码关注公众号并授权登录源码

PHP微信扫码登录看起来简单&#xff0c;但做起来有点麻烦&#xff0c;开发起来就会浪费很多的时间。 PHP判断是否首次关注公众号&#xff0c;扫码关注公众号获取微信用户头像、openid和省市等信息源码。 演示体验地址: https://www.skpan.cn/user/login.html 网盘下载地址:…

2023最新微信公众号无限回调系统源码/已修复BUG亲测可用

正文: 测试环境&#xff1a; Nginx 1.20.2 MySQL 5.6.50 PHP-7.2 1.创建站点 2.到根目录上传源码 3.创建数据库并导入 4.修改数据库信息 根目录/config.php 第5&#xff0c;6&#xff0c;7行 5.后台地址域名/admin 账号admin 密码123456 6.修改域名 根目录下 api.php 第…

Java微信公众号开发登录

MySQL基础开发篇 这部分的内容应该更合适那些刚入坑的朋友们或者是对于基础部分掌握不牢固的朋友,因此有一定经验的或者基础不错的可以自动跳至下一章内容阅读,这部分我仅把目录内容截图展示。 MySQL的优化以及管理维护 MySQL作为一款关系型数据库,SQL语句的优化是尤其重要的…

mysql 推送微信公众号_10分钟完成微信公众号第三方平台全网发布

背景&#xff1a;在微信公众平台配置服务器URL时&#xff0c;使用了新浪云SAE自带的二级域名&#xff0c;提交时出现一个安全风险的警告&#xff0c;网上查了下&#xff0c;许多服务平台和团队也遇到同样的问题。 经过一番研究 … 为什么会有安全风险的警告&#xff1f; 微信公…

springboot微信公众号管理系统vue内容文章文件上传jsp源码mysql

本项目为前几天收费帮学妹做的一个项目&#xff0c;Java EE JSP项目&#xff0c;在工作环境中基本使用不到&#xff0c;但是很多学校把这个当做编程入门的项目来做&#xff0c;故分享出本项目供初学者参考。 一、项目描述 这是一个基于springbootvue的微信公众号管理系统 二…

微信公众号迁移,需要做些什么

❤️ 个人主页&#xff1a;水滴技术 &#x1f680; 支持水滴&#xff1a;点赞&#x1f44d; 收藏⭐ 留言&#x1f4ac; &#x1f338; 订阅专栏&#xff1a;微信公众平台 文章目录 一、开通开发者二、设置IP白名单三、自定义菜单四、认证五、网页授权域名六、模板消息七、转换…

PHP微信公众号网页授权登录 扫码登录 获取用户基本信息

前言 现在微信登录是一个网站、APP的标配&#xff0c;所以微信授权登录是我们应该要掌握的。微信授权登录有4种方式&#xff1a; 1、通过微信开放平台2、通过认证的微信服务号3、通过认证的微信订阅号4、通过微信小程序曲线救国 今天我们就讲解的是微信服务号&#xff0c;通…

微信公众号多域名回调系统

介绍&#xff1a; 这是一款基于ThinkPHP6.0框架的微信公众号多域名回调系统。 微信公众号后台默认只能授权2个网页域名&#xff0c;用本系统可突破这个限制&#xff0c;用同一个公众号对接无限多个网站。网站后台支持回调域名白名单的管理&#xff0c;以及登录记录的查看。 本…

微信公众号授权获取用户信息及jwt登录

Java 微信公众号授权获取用户信息及jwt登录 &#xff01;&#xff01;&#xff01; 前言 前几篇文章小编分享过&#xff1a; 微信小程序授权获取用户手机号 jwt登录 (含源码)微信小程序支付 公众号支付 (含源码) 工作之余&#xff0c;分享下 “ 微信公众号授权 获取用户信…

手把手教程用Java实现微信公众号扫码登录功能

文章目录 前言一、环境准备二、使用步骤1. 使用微信工具包2. 创建数据表3. 登录页面代码逻辑4. 验证微信公众号登录 总结 前言 微信现今是我们必不可少的社交工具了&#xff0c;围绕微信这个生态实际上有很多东西可以做&#xff0c;我们经常会看到一些网站通过微信扫码进如公众…

[一维前缀和]leetcode303:区域和检索 - 数组不可变(easy)

题目&#xff1a; 题解&#xff1a; 一维前缀和&#xff0c;元素数组[0,j]的前缀和对应prefix[j1] 代码如下&#xff1a; class NumArray { private:vector<int> prefix; public://题解&#xff1a;一维前缀和NumArray(vector<int>& nums) {int nnums.size()…

前缀和矩阵前缀和

前缀和 前缀和是一种重要的预处理&#xff0c;能大大降低查询的时间复杂度。我们可以简单理解为“数列的前 n n n 项的和”。 例题 有 N N N 个的正整数放到数组 A A A 里&#xff0c;现在要求一个新的数组 B B B&#xff0c;新数组的第 i i i 个数 B [ i ] B[i] B[i]…

【算法基础】一维前缀和 + 二维前缀和

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前正在学习c和算法 ✈️专栏&#xff1a;【C/C】算法 &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章有啥瑕疵 希望大佬指点一二 如果文章对你有…