背景
使用微信公众号实现网页授权。
开始
1.微信网页授权的官方文档
2.申请微信测试公众号
从红框进入申请页面。
填写必要的信息,注意上图红框部分的域名需要可以外网能够访问,微信需要发送请求进行验证。我用的是内网穿透实现的,下面会说。
这里需配置授权成功后回调地址的域名,注意不要写http,https!这个坑我踩过。
3.内网穿透
我用的是natapp,免费的很稳定。详细信息可以看这个兄弟写的博文。
可以看这篇博文
4.实现
大体思路简单说一下,每生成一个授权二维码就在redis生成对应的key,用户扫描授权成功后获取用户信息,同时redis对应的key设置对应的value,保证一码扫一人。长轮询实现扫码成功通知前端。
controller
@Controller
@RequestMapping("/wechat")
@Api(tags = "微信相关接口")
public class WechatController {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
WechatService wechatService;
@RequestMapping("/notify")
@ResponseBody
public String wechatNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
String xml = wechatService.wechatXml(request);
String result = "";
String echostr = request.getParameter("echostr");
// 首次接入
if (echostr != null && echostr.length() > 1) {
result = echostr;
}
return result;
}
@GetMapping("/obtain_login_code")
@ApiOperation("获取登录二维码")
@ResponseBody
public Result<LoginCodeResDTO> obtainLoginCode(@RequestParam Integer proId) {
return ResultHandler.result(wechatService.obtainLoginCode(proId));
}
@GetMapping("/redirect")
public String redirectUri(@RequestParam String code, @RequestParam String state, @RequestParam Integer pid) {
try {
int flag = wechatService.redirectUri(code, state, pid);
//失效
if (flag == 0) {
return "redirect:../pages/lose.html";
}
return "redirect:../pages/success.html";
} catch (Exception e) {
logger.error("扫码失败----", e);
return "redirect:../pages/warn.html";
}
}
@PostMapping(value = "/query_code")
@ApiOperation("长轮询查询是否扫码成功")
@ResponseBody
public Result<WechatUserEntity> queryLoginState(@RequestBody QueryLoginStateReqDTO req) {
return ResultHandler.result(wechatService.queryLoginState(req));
}
}
service
@Service
public class WechatServiceImpl implements WechatService {
@Autowired
WechatBaseManager wechatBaseManager;
@Autowired
RedisTemplate redisTemplate;
@Autowired
WechatUserManager wechatUserManager;
@Autowired
ProjectWechatUserDAO projectWechatUserDAO;
@Value(value = "${wechat.redirect-url}")
private String redirectUrl;
@Override
public String wechatXml(HttpServletRequest request) throws Exception {
StringBuffer sb = new StringBuffer();
InputStream is = request.getInputStream();
InputStreamReader isr = new InputStreamReader(is, "UTF-8");
BufferedReader br = new BufferedReader(isr);
String s = "";
while ((s = br.readLine()) != null) {
sb.append(s);
}
// 微信发送过来的xml数据
String xml = sb.toString();
return xml;
}
@Override
@Transactional(rollbackFor = Exception.class)
public WechatUserEntity queryLoginState(QueryLoginStateReqDTO req) {
//生成二维码时存储用户信息的key
String scene = req.getScene();
if (redisTemplate.hasKey(scene)) {
LocalDateTime queryTime = LocalDateTime.now();
return wechatBaseManager.recurseQueryLogin(queryTime, scene);
} else {
throw new BusinessException(40010, "Redis不存在:" + scene);
}
}
@Override
public int redirectUri(String code, String state, Integer pid) {
JSONObject oauthJson = wechatBaseManager.getOpenIdByCode(code);