【微信】公众号授权绑定登录流程详解

在做微信公众号开发时,经常需要对公众号上面的菜单做授权登录,如果是首次登录还需要做微信openId和系统账号的绑定操作。

这里做如下假设:

  • 系统前端地址:http://www.test.com
  • 系统接口地址:http://api.test.com
  • 需要打开的页面地址:http://www.test.com/home/index

一、微信公众号配置

1、公众号注册以及实名认证
2、在“基本配置”中启用开发者密码(记得复制AppID、AppSecret),并设置IP白名单
3、在“公众号设置-功能设置”中,配置“业务域名、JS接口安全域名、网页授权域名”

注意:上面几个操起需要将微信授权文件(MP_verify_xxxxx.txt)下载存放在服务器上,需要让http://www.test.com/MP_verify_xxxxx.txt可以访问。
假设把文件放在目录/usr/share/nginx/file中,然后配置nginx,让该链接可以访问,例如:

# 微信授权文件通用匹配规则
location ~(MP_verify_)*\.(txt)$ {
    root   /usr/share/nginx/file;
}

【微信】公众号授权绑定登录流程详解_第1张图片

4、在“开发者工具-web开发者工具”中,绑定开发者微信号,便于在微信开发者工具中调试

【微信】公众号授权绑定登录流程详解_第2张图片

二、服务端开发

1、引入第三方微信公众号sdk

这里推荐开源项目WxJava

在pom.xml中引入第三方jar包

<dependency>
    <groupId>com.github.binarywanggroupId>
    <artifactId>weixin-java-mpartifactId>
    <version>4.5.0version>
dependency>

2、配置微信公众号服务

1)将复制下来的AppID、AppSecret配置在application.yml

wx:
  appId: wxd8e8db2818fxxxxx
  appSecret: 4a22ab04b25eb155bd8b6a540cxxxxx
  # 前端账号绑定页面url
  bindUrl: http://www.test.com/wxBind
  # 后端微信授权回调url
  callback: http://api.test.com/wx/auth/callback

2)新建配置属性类WxProperties.java

@ConfigurationProperties(prefix = "wx")
@Data
public class WxProperties {

    private String appId;
    private String appSecret;
    private String bindUrl;
    private String callback;
}

3)新增配置类WxConfig.java

@Configuration
@EnableConfigurationProperties(WxProperties.class)
public class WxConfig {

    private WxProperties wxProperties;

    public WxConfig(WxProperties wxProperties) {
        this.wxProperties = wxProperties;
    }

    @Bean
    public WxMpService wxMpService(){
        WxMpService wxMpService = new WxMpServiceImpl();
        WxMpDefaultConfigImpl configStorage = new WxMpDefaultConfigImpl();
        configStorage.setAppId(wxProperties.getAppId());
        configStorage.setSecret(wxProperties.getAppSecret());
        wxMpService.setWxMpConfigStorage(configStorage);
        return wxMpService;
    }
}

3、编写回调及绑定接口

1)新建微信授权回调接口Controller,编写授权回调接口

如果用户还未绑定,需要把openId传给前端,前端在绑定登录时,一起作为参数传回到后端的绑定接口

@Slf4j
@Controller
@RequestMapping("/wx/auth")
public class WxAuthController {
    @Resource
    private WxMpService wxMpService;
    @Resource
    private WxProperties wxProperties;

    @RequestMapping("/callback")
    public String callback(Model model, String state, String code) throws WxErrorException {
        log.info("wx callback, code:{},state:{}", code, state);
        WxOAuth2AccessToken accessToken = wxMpService.getOAuth2Service().getAccessToken(code);
        String openId = accessToken.getOpenId();
        // 根据openId查找账号,如果不存在则新增绑定
        String sysUserId = sysUserService.loadByWxOpenId(openId);
        if (StringUtils.isNotBlank(sysUserId)) {
            // 执行登录
            LoginUser loginUser = sysUserService.getUserById(sysUserId);
            // 跳转到前端页面地址
            if (StringUtils.isNotBlank(state) && StringUtils.startsWith(state, "http")) {
                // 生成登录Token,返回给前端
                // 示例代码是通过Jwt生成Token,然后存储在Redis中
                String token = saveToken(loginUser);
                model.addAttribute("token", token);
                log.info("公众号自动登录,userId:{},wxOpenId:{}", loginUser.getId(), openId);
                return "redirect:" + state + "?token=" + token;
            }
        }
        log.info("公众号未绑定,wxOpenId:{}", openId);
        // 找不到已绑定记录,跳转到绑定页面,执行绑定
        return "redirect:" + wxProperties.getBindUrl() + "?wxOpenId=" + openId + "&state=" + state;
    }
    
    // ... 暂时忽略其他方法 ....//
}

2)编写账号绑定接口

先校验账号密码,然后把微信openId和用户userId绑定,下次登录时候就可以根据openId查询到userId

@Data
public class WxBindVo {
    @ApiModelProperty(value = "微信openId")
    private String wxOpenId;
    @ApiModelProperty(value = "账号")
    private String username;
    @ApiModelProperty(value = "密码")
    private String password;
}

@RequestMapping("/bind")
@ResponseBody
public Result<JSONObject> bind(@RequestBody WxBindVo wxBindVo) throws WxErrorException {
    log.info("wx bind, {}", wxBindVo);
    Result<JSONObject> result = new Result<>();
    JSONObject obj = new JSONObject();
    // 执行绑定,然后自动登录,等完成后跳转到原来的页面
    LoginUser loginUser = sysUserService.checkUser(wxBindVo.getUsername(), wxBindVo.getPassword());
    if (loginUser != null) {
        //绑定微信OpenId
        sysUserService.saveWxAccount(loginUser.getId(), wxBindVo.getWxOpenId());
        //用户登录信息
        obj.put("userInfo", loginUser);
        obj.put("token", saveToken(loginUser));
        result.setResult(obj);
        result.setSuccess(true);
        result.setCode(200);
        log.info("微信公众号绑定后自动登录,userId:{}, wxOpenId:{}", loginUser.getId(), wxBindVo.getWxOpenId());
        return result;
    }
    result.setResult(obj);
    result.setSuccess(false);
    result.setMessage("公众号登录失败,请联系管理员");
    return result;
}

3)编写微信公众号授权菜单入口

有了这个入口方法,只要将微信公众号菜单统一配置到这就可以,将需要打开的页面url传给state参数。

例如:http://api.test.com/wx/auth/index?state=http://www.test.com/home/index

/**
 * 微信公众号授权菜单入口
 * @param state 授权登录跳转的页面url
 */
@RequestMapping("/index")
public String index(String state) {
    String url = wxProperties.getCallback();
    String authorizationUrl = wxMpService.getOAuth2Service().buildAuthorizationUrl(url, WxConsts.OAuth2Scope.SNSAPI_BASE, URIUtil.encodeURIComponent(state));
    log.info("authorizationUrl = {}", authorizationUrl);
    return "redirect:" + authorizationUrl;
}

三、前端页面开发

当然,还有前端绑定页面开发,这里主要讲解流程,前端代码省略

四、在公众号中配置菜单

打开公众号“内容于互动-自定义菜单”,添加添加菜单,输入菜单名单和跳转网页链接

这里网页链接假设是:http://api.test.com/wx/auth/index?state=http://www.test.com/home/index

【微信】公众号授权绑定登录流程详解_第3张图片

四、相关流程图

1、公众号授权登录时序图

【微信】公众号授权绑定登录流程详解_第4张图片

2、公众号授权登录流程图

【微信】公众号授权绑定登录流程详解_第5张图片

你可能感兴趣的:(微信生态,微信)