在做微信公众号开发时,经常需要对公众号上面的菜单做授权登录,如果是首次登录还需要做微信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;
}
4、在“开发者工具-web开发者工具”中,绑定开发者微信号,便于在微信开发者工具中调试
二、服务端开发
1、引入第三方微信公众号sdk
这里推荐开源项目WxJava
在pom.xml中引入第三方jar包
<dependency><groupId>com.github.binarywang</groupId><artifactId>weixin-java-mp</artifactId><version>4.5.0</version>
</dependency>
2、配置微信公众号服务
1)将复制下来的AppID、AppSecret
配置在application.yml
中
wx:appId: wxd8e8db2818fxxxxxappSecret: 4a22ab04b25eb155bd8b6a540cxxxxx# 前端账号绑定页面urlbindUrl: http://www.test.com/wxBind# 后端微信授权回调urlcallback: 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;}@Beanpublic 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 {@Resourceprivate WxMpService wxMpService;@Resourceprivate 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) {//绑定微信OpenIdsysUserService.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