【微信登录】APP/网站应用的微信扫码登录

目录

一、开发文档说明

1、移动应用APP端(安卓/苹果)的微信登录

2、网站应用PC端的微信扫码登录

3、微信开放平台申请账号

二、业务接口开发

1、配置

2、第一步:请求CODE

3、第二步:通过code获取access_token

4、工具方法

5、测试

扫描二维码关注公众号,回复: 12141667 查看本文章

一、开发文档说明

1、移动应用APP端(安卓/苹果)的微信登录

准备工作

移动应用微信登录是基于OAuth2.0 协议标准构建的微信 OAuth2.0 授权登录系统。

在进行微信 OAuth2.0 授权登录接入之前,在微信开放平台注册开发者帐号,并拥有一个已审核通过的移动应用,并获得相应的 AppID 和 AppSecret,申请微信登录且通过审核后,可开始接入流程

  1. 目前移动应用上微信登录只提供原生的登录方式,需要用户安装微信客户端才能配合使用。
  2. 对于Android应用,建议总是显示微信登录按钮,当用户手机没有安装微信客户端时,请引导用户下载安装微信客户端。
  3. 对于iOS应用,考虑到iOS应用商店审核指南中的相关规定,建议开发者接入微信登录时,先检测用户手机

授权流程说明

微信 OAuth2.0 授权登录让微信用户使用微信身份安全登录第三方应用或网站,在微信用户授权登录已接入微信 OAuth2.0 的第三方应用后,第三方可以获取到用户的接口调用凭证(access_token),通过 access_token 可以进行微信开放平台授权关系接口调用,从而可实现获取微信用户基本开放信息和帮助用户实现基础开放功能等。

微信 OAuth2.0 授权登录目前支持 authorization_code 模式,适用于拥有 server 端的应用授权。该模式整体流程为:

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

获取 access_token 时序图:

注:具体请参考官网开发文档,这里只摘抄部分:https://developers.weixin.qq.com/doc/oplatform/Mobile_App/WeChat_Login/Development_Guide.html

2、网站应用PC端的微信扫码登录

网站应用微信登录是基于OAuth2.0协议标准构建的微信OAuth2.0授权登录系统。 在进行微信OAuth2.0授权登录接入之前,在微信开放平台注册开发者帐号,并拥有一个已审核通过的网站应用,并获得相应的AppIDAppSecret,申请微信登录且通过审核后,可开始接入流程。

PC端其实与移动应用端差不多,我们后端开发时,提供给PC端、APP端是统一的接口,些许差异再具体业务逻辑层处理。对接微信,具体参考官网:https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Wechat_Login.html

3、微信开放平台申请账号

上面对接微信登录接口的开发文档中,准备工作已经明确说明:在进行微信 OAuth2.0 授权登录接入之前,在微信开放平台注册开发者帐号,并拥有一个已审核通过的移动应用/网站应用,并获得相应的 AppID 和 AppSecret,申请微信登录且通过审核后,可开始接入流程。具体请登录去申请:https://open.weixin.qq.com/

如下,是我已经申请审核通过的一个网站应用,具体直接创建一步一步跟着填写即可,最后的授权回调域写自己的网站域名即可,无需加http或https,如:www.baidu.com

二、业务接口开发

注:因为采用前后端分离,这里只展示提供后端接口的业务开发流程。

项目采用SpringBoot构建,配置中心与注册中心使用nacos,可将一些配置信息放在nacos上。

1、配置

(1)网站应用-PC

将在微信开放平台申请到的网站应用(PC)的相关信息放到配置文件(appId、appSercet等),当然,微信的接口地址基本是固定不变的,也可以写到常量类中。

其中,callBack配置的是获取微信授权的code后的回调地址(公网地址),可以是后端接口或前端接口(前后端分离,由前端再调后端)。

(2)移动应用-Android、IOS

其中,微信的接口地址与PC端一样,就无需再配置

2、第一步:请求CODE

这里的配置信息,统一由后端接口获取并提供,无需前端写死,方便以后可以直接配置中心修改即可;然后再由前端发起调用微信方,用户授权后,就会回调返回code

(1) 网站应用-PC

    /**
     * pc端获取微信二维码地址
     * <p>
     * 返回code地址等参数给前端,由前端js请求跳转二维码
     * 用户扫码确认授权后,微信会回调返回code、state
     * <p>
     *
     * @return
     * @throws
     */
    @RequestMapping("/pc/weixin/login/getCodeUrl")
    public Result getCodeUrl() throws Exception {
        //String codeUrl = "https://open.weixin.qq.com/connect/qrconnect?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE";
        String codeUrl = pcConfig.getCodeUrl();

        // state用于保持请求和回调的状态,授权请求后原样带回给第三方。
        // 该参数可用于防止csrf攻击(跨站请求伪造攻击),建议第三方带上该参数,可设置为简单的随机数加session进行校验
        // 注:这里采用AES加密,使用当前时间作为明文加密,x小时内有效
        String encryptState = AesUtils.encrypt(DateUtils.getNowYYYYMMdd(), AesUtils.getAssetsDevPwdField());

        Map<String,String> map = new HashMap<>();
        map.put("appId",pcConfig.getAppId());
        map.put("redirectUrl",pcConfig.getCallBack());
        map.put("scope",pcConfig.getScope());
        map.put("state",encryptState);
        map.put("codeUrl",codeUrl);

        return Result.success(map);
    }

(2)移动应用-Android、IOS

    /**
     * APP获取移动应用的appId等配置
     *
     * @return
     * @throws
     */
    @RequestMapping("/app/weixin/login/getAppConfig")
    public Result getAppConfig() throws Exception {

        String appId = appConfig.getAppId();

        // 采用AES加密,使用当前时间作为明文加密,x小时内有效
        String encryptState = AesUtils.encrypt(DateUtils.getNowYYYYMMdd(), AesUtils.getAssetsDevPwdField());
        Map<String, String> map = new HashMap<>();
        map.put("appId", appId);
        map.put("state", encryptState);

        return Result.success(map);
    }

当用户授权微信登录时,微信会回调,返回codestate

返回说明

用户允许授权后,将会重定向到redirect_uri(也就是我们上面配置的callBack)的网址上,并且带上code和state参数

redirect_uri?code=CODE&state=STATE

若用户禁止授权,则重定向后不会带上code参数,仅会带上state参数

redirect_uri?state=STATE

3、第二步:通过code获取access_token

通过code获取access_token

https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code

参数说明

参数 是否必须 说明
appid 应用唯一标识,在微信开放平台提交应用审核通过后获得
secret 应用密钥AppSecret,在微信开放平台提交应用审核通过后获得
code 填写第一步获取的code参数
grant_type 填authorization_code

因为项目采用前后端分离,这里PC端的callBack回调地址是填的前端地址,再由前端调用后端接口(/weixin/login/callBack

大致流程用户授权--->code--->获取access_token、openid等--->获取微信用户的基本信息--->注册/登录

    /**
     * 授权回调,微信返回code、state---【PC端、APP端公用】
     * <p>
     * 1、然后通过code、appid、secret去请求获取access_token、openid
     * 2、最后通过access_token、openid去获取用户信息(unionid)
     * <p>
     */
    @RequestMapping("/weixin/login/callBack")
    public Result callBack(@RequestBody WeixinLoginDTO dto, HttpServletRequest request) throws Exception {
        log.info("【微信登录】回调,code:{},state:{}", dto.getCode(), dto.getState());

        try{
            // AES解密state
            boolean b = checkState(dto.getState());
            if(!b){
                log.error("【微信登录】回调异常,state已失效或被篡改:{}", dto.getState());
                return Result.error(ResultCode.STATE_IS_INVALID);
            }

            // 先判断缓存中是否已存在(微信获取access_token的接口code只能使用一次)
            String weixinUserJson = (String) redisUtils.get(RedisPrefix.weixin_user_info, dto.getCode());
            if (StringUtils.isNotBlank(weixinUserJson)) {
                // 直接登录
                return this.weixinLogin(dto.getCode(),weixinUserJson, dto.getSource(), request);
            }

            //1.通过code获取access_token
            //String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";
            String accessTokenUrl = pcConfig.getAccessTokenUrl();

            if ("PC".equals(dto.getSource())) {//pc端
                accessTokenUrl = accessTokenUrl.replace("APPID", pcConfig.getAppId()).replace("SECRET", pcConfig.getAppSecret()).replace("CODE", dto.getCode());
            } else {// app端
                accessTokenUrl = accessTokenUrl.replace("APPID", appConfig.getAppId()).replace("SECRET", appConfig.getAppSecret()).replace("CODE", dto.getCode());
            }

            HttpClientResult tokenResult = HttpClientUtils.doGet(accessTokenUrl);
            log.info("【微信登录】获取access_token结果:{}",tokenResult);
            if (200==tokenResult.getCode()) {
                JSONObject tokenInfoObject = JSON.parseObject(tokenResult.getContent());

                if (StringUtils.isNotEmpty(tokenInfoObject.getString("errcode"))) {
                    log.error("【微信登录】获取access_token失败:{}", tokenInfoObject.getString("errmsg"));
                    return Result.error(ResultCode.WEIXIN_LOGIN_ERROR);
                }

                //2.通过access_token和openid获取用户信息
                //String userInfoUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID";
                String userInfoUrl = pcConfig.getUserInfoUrl();
                userInfoUrl = userInfoUrl.replace("ACCESS_TOKEN", tokenInfoObject.getString("access_token")).replace("OPENID", tokenInfoObject.getString("openid"));
                HttpClientResult weixinUserResult = HttpClientUtils.doGet(userInfoUrl);
                log.info("【微信登录】获取微信用户信息结果:{}",weixinUserResult);
                if (200==weixinUserResult.getCode()) {

                    JSONObject weixinUserObject = JSON.parseObject(weixinUserResult.getContent());

                    if (StringUtils.isNotEmpty(weixinUserObject.getString("errcode"))) {
                        log.error("【微信登录】获取微信用户信息失败:{}", weixinUserObject.getString("errmsg"));
                        return Result.error(ResultCode.WEIXIN_LOGIN_ERROR);
                    }
                    // todo 登录或注册
                    return this.weixinLogin(dto.getCode(),weixinUserResult.getContent(), dto.getSource(), request);
                }
            }
        }catch (Exception e){
            log.error("================【微信登录】回调接口异常:{}",e.getMessage());
        }
        log.error("【微信登录】回调失败!");
        return Result.error(ResultCode.WEIXIN_LOGIN_ERROR);
    }

其中,“todo 登录或注册”就是你自己要根据业务需求进行具体的注册/登录业务逻辑开发。

返回说明:通过access_token和openid获取用户信息

正确的Json返回结果:

{
    "openid":"OPENID",
    "nickname":"NICKNAME",
    "sex":1,
    "province":"PROVINCE",
    "city":"CITY",
    "country":"COUNTRY",
    "headimgurl": "https://thirdwx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/0",
    "privilege":[
        "PRIVILEGE1",
        "PRIVILEGE2"
    ],
    "unionid": " o6_bmasdasdsad6_2sgVt7hMZOPfL"

}

4、工具方法

5、测试

PC端扫描授权登录,看能否回调后获取微信用户信息

注:由于项目采用前后端分离,本文仅提供后端接口开发说明,大致流程类似,具体的请求参数与响应信息,参考官网即可。

参考:

https://open.weixin.qq.com/

https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Wechat_Login.html

史上最强Tomcat8性能优化

阿里巴巴为什么能抗住90秒100亿?--服务端高并发分布式架构演进之路

B2B电商平台--ChinaPay银联电子支付功能

学会Zookeeper分布式锁,让面试官对你刮目相看

SpringCloud电商秒杀微服务-Redisson分布式锁方案

查看更多好文,进入公众号--撩我--往期精彩

一只 有深度 有灵魂 的公众号0.0

猜你喜欢

转载自blog.csdn.net/a1036645146/article/details/111227147