zoukankan      html  css  js  c++  java
  • 微信公众号测试-微信授权登录

    一、微信官方文档

    https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html

    二、准备工作

    1)一个域名

    ● 自己备案申请一个域名
    ● 使用内网穿透工具

    我这里使用的是内网穿透工具闪库
    使用方法 >点这里< 这是我以前使用的内网穿透工具,使用方法都差不多的

    2)微信公众平台测试号配置

    ① 配置JS接口安全域名(不要带http)
    image
    ② 配置网页授权回调页面域名(不要带http)
    image
    image
    ③ 扫码关注测试号
    image

    3)获取公众平台测试号的 AppID 和 AppSecret

    image

    三、授权步骤

    1.第三方发起微信授权登录请求,微信用户允许授权第三方应用后,微信会拉起应用或重定向到第三方网站,并且带上授权临时票据 code 参数;
    2.通过 code 参数加上 AppID 和 AppSecret 等,通过 API 换取 access_token;
    3.通过 access_token 进行接口调用,获取用户基本数据资源或帮助用户实现基本操作。

    image

    四、实例

    - 项目结构
    使用 SpringBoot 构建项目

    image

    1)Maven依赖

    <!--用于对JSON格式的数据进行解析和打包-->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.75</version>
    </dependency>
    <!--支持 HTTP 通讯,实现了所有 HTTP 的方法等-->
    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.5.3</version>
    </dependency>
    <!--lombok-->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <!--Thymeleaf-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    <!--web-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    

    2)配置application.yaml文件

    # 端口号
    server:
      port: 8080
    # 微信公众号配置
    weChat:
      appid: xxxxx # 微信测试号ID
      appsecret: xxxxxxx # 微信测试号Secret
      token: xxxx # Token
      backUrl: http://byr1vl4.nat.ipyingshe.com # 你的域名
      backApi: /callBack # 登录回调的API
    

    3)配置拦截器解决跨域问题(如跨域没问题,可忽略)

    import org.springframework.stereotype.Component;
    import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    @Component
    public class CrossInterceptor extends HandlerInterceptorAdapter {
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            response.setHeader("Access-Control-Allow-Origin", "*");
            response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
            response.setHeader("Access-Control-Max-Age", "3600");
            response.setHeader("Access-Control-Allow-Headers", "*");
            response.setHeader("Access-Control-Allow-Credentials", "true");
            return true;
        }
    }
    

    4)公众平台测试号接口配置(可跳过忽略)

    测试号配置

    URL:填写 http+前面添加的域名+校验API
    Token:任意字符串,只要和后端相对应就行

    image

    DecriptUtil工具类:SHA1加密

    import java.security.MessageDigest;
    import java.security.NoSuchAlgorithmException;
    
    public class DecriptUtil {
    
        /**
         * @param decript
         * @return
         */
        public static String SHA1(String decript) {
            try {
                MessageDigest digest = MessageDigest
                        .getInstance("SHA-1");
                digest.update(decript.getBytes());
                byte messageDigest[] = digest.digest();
                // Create Hex String
                StringBuffer hexString = new StringBuffer();
                // 字节数组转换为 十六进制 数
                for (int i = 0; i < messageDigest.length; i++) {
                    String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);
                    if (shaHex.length() < 2) {
                        hexString.append(0);
                    }
                    hexString.append(shaHex);
                }
                return hexString.toString();
    
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
            return "";
        }
    }
    

    接口校验,接入微信公众平台

    Controller

    @Controller
    public class WxAuthController {
    
        @Autowired
        private WxAuthService wxAuthService;
    
        /**
         * 校验接入微信公众平台开发
         *
         * @param signature
         * @param timestamp
         * @param nonce
         * @param echostr
         * @return
         */
        @GetMapping("/wxSignatureCheck")
        @ResponseBody
        public String wxSignatureCheck(
                @RequestParam(value = "signature") String signature,
                @RequestParam(value = "timestamp") String timestamp,
                @RequestParam(value = "nonce") String nonce,
                @RequestParam(value = "echostr") String echostr) {
            return wxAuthService.wxSignatureCheck(signature, timestamp, nonce, echostr);
        }
    }
    

    Service

    import com.cyan.wx_auth_demo.utils.DecriptUtil;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Service;
    
    import java.util.ArrayList;
    import java.util.Arrays;
    
    @Slf4j
    @Service
    public class WxAuthService {
    
        @Value("${weChat.token}")
        private String token;
    
        /**
         * 验证签名
         *
         * @param signature
         * @param timestamp
         * @param nonce
         * @param echostr
         * @return 校验成功返回echostr,否则为null
         */
        public String wxSignatureCheck(String signature, String timestamp, String nonce, String echostr) {
            ArrayList<String> array = new ArrayList<>();
            array.add(signature);
            array.add(timestamp);
            array.add(nonce);
    
            //排序
            String sortString = sort(token, timestamp, nonce);
            //加密
            String mytoken = DecriptUtil.SHA1(sortString);
            //校验签名
            if (mytoken != null && mytoken != "" && mytoken.equals(signature)) {
                log.info("签名校验通过");
                //如果检验成功输出 echostr,微信服务器接收到此输出,才会确认检验完成。
                return echostr;
            } else {
                log.info("签名校验失败");
                return null;
            }
        }
    
        /**
         * 排序方法
         *
         * @param token
         * @param timestamp
         * @param nonce
         * @return
         */
        public static String sort(String token, String timestamp, String nonce) {
            String[] strArray = {token, timestamp, nonce};
            Arrays.sort(strArray);
    
            StringBuilder sbuilder = new StringBuilder();
            for (String str : strArray) {
                sbuilder.append(str);
            }
    
            return sbuilder.toString();
        }
    }
    

    5)实现微信授权登录

    AuthUtil工具类

    import com.alibaba.fastjson.JSONObject;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.http.HttpEntity;
    import org.apache.http.client.ClientProtocolException;
    import org.apache.http.client.methods.CloseableHttpResponse;
    import org.apache.http.client.methods.HttpGet;
    import org.apache.http.impl.client.CloseableHttpClient;
    import org.apache.http.impl.client.HttpClients;
    import org.apache.http.util.EntityUtils;
    
    import java.io.IOException;
    
    @Slf4j
    public class AuthUtil {
    
        public static JSONObject doGetJson(String url) throws ClientProtocolException, IOException {
            JSONObject jsonObject = null;
    
            //创建HttpClient对象,发送请求,获取数据
            CloseableHttpClient httpClient = HttpClients.createDefault();
            //创建httpGet方法对象
            HttpGet httpGet = new HttpGet(url);
            //设置请求头
            httpGet.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36");
            //发送请求,获取响应的数据
            log.info("请求地址:{}", url);
            CloseableHttpResponse response = httpClient.execute(httpGet);
    
            //获取响应体
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                // 把返回的结果转换为JSON对象
                String result = EntityUtils.toString(entity, "GB2312");
                log.info("响应结果:{}", result);
                jsonObject = JSONObject.parseObject(result);
            }
            httpGet.releaseConnection();
            return jsonObject;
        }
    }
    

    网站主页,用户点击登录按钮跳转登录授权页面

    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class IndexController {
    
        /**
         * 登录按钮
         * http://byr1vl4.nat.ipyingshe.com/index
         *
         * @return
         */
        @GetMapping("/index")
        public String login() {
            return "<a href='http://byr1vl4.nat.ipyingshe.com/authorize'>微信登录</a>";
        }
    }
    

    网页登录授权控制类

    import com.alibaba.fastjson.JSONObject;
    import com.cyan.wx_auth_demo.utils.AuthUtil;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    import java.io.IOException;
    import java.net.URLEncoder;
    
    @Slf4j
    @Controller
    public class WxAuthController {
    
        @Value("${weChat.appid}")
        private String appid;
    
        @Value("${weChat.appsecret}")
        private String appsecret;
    
        @Value("${weChat.backUrl}")
        private String backUrl;
    
        @Value("${weChat.backApi}")
        private String backApi;
    
        /**
         * 一、公众号微信登录授权
         * <p>
         * 通过微信接口获取code
         * 1、如果用户同意授权,页面将跳转至 redirect_uri/?code=CODE&state=STATE
         * 2、获取到 code 与 state
         *
         * @return
         */
        @GetMapping("/authorize")
        public String authorize() throws IOException {
    
            // 第一步:用户同意授权,获取code
            String redirectUrl = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" + appid
                    + "&redirect_uri=" + URLEncoder.encode(backUrl + backApi, "UTF-8")
                    + "&response_type=code"
                    + "&scope=snsapi_userinfo"
                    + "&state=STATE#wechat_redirect";
    
            // 重定向地址
            System.out.println("重定向至微信登录授权地址: " + redirectUrl);
            return "redirect:" + redirectUrl;
        }
    
        /**
         * 二、回调获取用户信息
         *
         * @param code 第一步获取到的code
         * @return
         * @throws IOException
         */
        @GetMapping("/callBack")
        @ResponseBody
        public String callBack(String code) throws IOException {
    
            // 1、通过code(authorize方法获取)换取网页授权access_token
            String accessTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?"
                    + "appid=" + appid
                    + "&secret=" + appsecret
                    + "&code=" + code
                    + "&grant_type=authorization_code";
            JSONObject accessTokenObj = AuthUtil.doGetJson(accessTokenUrl);
    
            // 2、拉取用户信息,传参 access_token 和 openId
            String userinfoUrl = "https://api.weixin.qq.com/sns/userinfo?"
                    + "access_token=" + accessTokenObj.getString("access_token")
                    + "&openid=" + accessTokenObj.getString("openId")
                    + "lang=zh_CN";
            JSONObject userInfoObj = AuthUtil.doGetJson(userinfoUrl);
    
            // 将用户信息返回到前端
            StringBuilder sb = new StringBuilder();
            sb.append("<div>");
            sb.append("<h3>授权成功</h3>");
            sb.append("<img alt='头像' src='" + userInfoObj.getString("headimgurl") + "'>");
            sb.append("<p>" + userInfoObj.getString("nickname") + "</p>");
            sb.append("<p>" + userInfoObj.getString("province") + "</p>");
            sb.append("</div>");
            return sb.toString();
        }
    }
    

    运行结果

    ① 登录页
    image
    ② 授权页
    image
    ② 授权成功页
    image

    到此,微信授权登录成功,如果有运行问题请自行调试,我这边能正常运行的。

  • 相关阅读:
    Redis订阅和发布模式和Redis事务
    Redis介绍和环境安装
    Redis基本数据类型
    MongoDB导入导出以及数据库备份
    MongoDB-python的API手记
    MongoDB对应SQL语句
    判断是否微信浏览器访问并得到微信版本号
    windows 下编译php扩展库pecl里的扩展memcache
    用PHPExcel类读取excel文件的内容
    用excel.php类库导出excel文件
  • 原文地址:https://www.cnblogs.com/Dm920/p/15303677.html
Copyright © 2011-2022 走看看