微信授权登陆

1.官方网站:微信登录功能 / 网页应用授权用户信息变更 (qq.com)

2.登陆流程:

和登陆微信没关系,是用户的微信号,和我程序的程序编号(微信给的 目前用的老师的),去请求微信的接口,微信给这个用户一个token,这个token在本系统中 只和该用户对应。登陆成功。

实际上有点出入,是用户扫码后确定登录后,自动去请求微信的接口,我拿不到用户的微信号。

微信授权登陆_第1张图片

3.具体实现

1》用户在页面点击登陆按钮,前端发送请求给后端

  • 2》后端接收到请求,通过重定向去请求微信接口。返回重定向地址后,此时浏览器页面会自动新建一个页签,是微信的二维码登陆界面。

    重定向到微信接口需要参数 appid这里使用谷粒学院老师的。

    重定向地址是自己写的,在扫码之后微信会访问这个地址。

    其他参数不清楚。

    @GetMapping("login")
        public String genQrConnect(HttpSession session) {
            // 微信开放平台授权baseUrl
            String baseUrl = "https://open.weixin.qq.com/connect/qrconnect" +
                    "?appid=%s" +
                    "&redirect_uri=%s" +
                    "&response_type=code" +
                    "&scope=snsapi_login" +
                    "&state=%s" +
                    "#wechat_redirect";
            // 回调地址
            String redirectUrl = ConstantWxUtils.REDIRECT_URL; //获取业务服务器重定向地址
            try {
                redirectUrl = URLEncoder.encode(redirectUrl, "UTF-8"); //url编码
            } catch (UnsupportedEncodingException e) {
                throw new GuLiExeception(20001, e.getMessage());
            }
            // 防止csrf攻击(跨站请求伪造攻击)
            //String state = UUID.randomUUID().toString().replaceAll("-", "");//一般情况下会使用一个随机数
            String state = "imhelen";//为了让大家能够使用我搭建的外网的微信回调跳转服务器,这里填写你在ngrok的前置域名
    
            // 采用redis等进行缓存state 使用sessionId为key 30分钟后过期,可配置
            //键:"wechar-open-state-" + httpServletRequest.getSession().getId()
            //值:satte
            //过期时间:30分钟
            //生成qrcodeUrl
            String qrcodeUrl = String.format(
                    baseUrl,
                    ConstantWxUtils.APP_ID,
                    redirectUrl,
                    state);
            return "redirect:" + qrcodeUrl;
        }

    微信授权登陆_第2张图片

    3.用户在扫码登陆之后,微信会访问第二步携带的回调接口,并携带这个一个临时参数,在controller中获得此参数后,携带secret,访问正式的三方登陆接口,会返回access_token,这个access_token就是 该微信用户,在本系统中,唯一的token,token和用户是一对一的关系,微信登陆完成。

    获得这个token后,可以再请求一次微信用户信息接口,获取用户的头像、微信名信息。

    在获取完用户的头像、微信名信息后,重定向到前端地址,以重新加载刚才的扫码页面,并且在路径中携带token,前端发现路径中有token后,获取这个token,并携带这个token访问获取用户信息接口,获取用户信息。

        @GetMapping("callback")
        public String callBack(String code, String state) {
            //从redis中将state获取出来,和当前传入的state作比较
            //如果一致则放行,如果不一致则抛出异常:非法访问
            //向认证服务器发送请求换取access_token
            String baseAccessTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token" +
                    "?appid=%s" +
                    "&secret=%s" +
                    "&code=%s" +
                    "&grant_type=authorization_code";
    
            String accessTokenUrl = String.format(baseAccessTokenUrl,
                    ConstantWxUtils.APP_ID,
                    ConstantWxUtils.APP_SECRECT,
                    code);
            // 使用httpClient发送请求,得到返回结果
            JSONObject accesstokenInfo = HttpClientUtils.httpGet(accessTokenUrl);
            String access_token = (String) accesstokenInfo.get("access_token");
            String openid = (String) accesstokenInfo.get("openid");
    
            LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper();
            lambdaQueryWrapper.eq(UcenterMember::getOpenid, openid);
            UcenterMember checkUser = ucenterMemberService.getOne(lambdaQueryWrapper);
            if (checkUser == null) {
                //访问微信的资源服务器,获取用户信息
                String baseUserInfoUrl = "https://api.weixin.qq.com/sns/userinfo" +
                        "?access_token=%s" +
                        "&openid=%s";
    
                String userInfoUrl = String.format(baseUserInfoUrl, access_token, openid);
                try {
                    JSONObject jsonObject = HttpClientUtils.httpGet(userInfoUrl);
                    String nickName = jsonObject.getString("nickname");
                    String headUrl = jsonObject.getString("headimgurl");
                    UcenterMember ucenterMember = new UcenterMember(openid, nickName, headUrl);
                    ucenterMemberService.save(ucenterMember);
                    String jwtToken = JwtUtils.getJwtToken(ucenterMember.getId(), nickName);
                    return "redirect:http://localhost:3000?guli_token=" + jwtToken;
                } catch (Exception e) {
                    throw new GuLiExeception(20001, "用户未注册,获取腾讯用户信息失败");
                }
            }
            String jwtToken = JwtUtils.getJwtToken(checkUser.getId(), checkUser.getNickname());
            String temp=JwtUtils.getMemberIdByJwtTokenString(jwtToken);
            System.out.println("=======");
            System.out.println(temp);
            return "redirect:http://localhost:3000?guli_token="+jwtToken;
        }

    前端代码, 前端发现路径中有token后,获取这个token,并携带这个token访问获取用户信息接口,获取用户信息。这是default.vue,当用户没有输入访问的具体地址时,默认访问此界面。

    
    

     后端接收到前端发送的token,根据这个token查询用户信息并返回(用户信息在第三步上面已经获取到,并且保存数据库,这里只查就可以)

        @GetMapping("/info")
        public R geInfo(HttpServletRequest request) {
            String headers = "";
            Enumeration names = request.getHeaderNames();
            while (names.hasMoreElements()) {
                String name = names.nextElement();
                String value = request.getHeader(name);
                headers += name + "=" + value + "\n";
            }
            System.out.println(headers + "请求用户信息请求头如上");
    
            String memberId = JwtUtils.getMemberIdByJwtToken(request);
            UcenterMember uCenterMember = ucenterMemberService.getById(memberId);
            return R.ok().data("member", uCenterMember);
        }

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