Bootstrap

java : 实现微信网页授权,超详细!

背景

使用微信公众号实现网页授权。

开始

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);
      
;