隐藏

微信扫码登录前后端实现(SpringBoot、Vue.js)

发布:2024/1/10 22:31:18作者:管理员 来源:本站 浏览次数:706

文章目录


           背景

           效果预览

           流程介绍

           前端部分

               生成微信登录二维码

                   微信 wxLogin.js

                   创建方法

           后端部分

                   认证服务器Nginx配置

                   重定向到Java程序处理


背景


这里微信扫码登录,没有采用轮询、没有采用WebSocket推送,而是由: 扫码后重定向 -> 微信服务器 -> 我方统一认证服务器 -> 指定业务服务器 -> 返回code前端处理结果执行登录。


因为微信PC网站登录,回调合法域名、不管是子域名还是主域名仅能填写一个,所以如果有多个登录环境的情况下,就需要业务方有一台统一的服务来处理分发扫码请求。


如需进行二维码过期、自动刷新二维码等操作,可自行实现,不在本文介绍范围内。

效果预览


image-20210926143053685

流程介绍


登录过程客户端请求情况


image-20210926151833965


   从上述网络资源请求记录中可以看到,从扫码确认登陆后,至少经历了两次302(重定向)


       一次是由微信产生code后重定向到Js中配置的redirect_uri去并携带code及state字段。

       二次是由Nginx服务器判断该请求属于什么业务的,并将Host替换为指定配置服务,重定向过去。

       最后由业务服务器接收到请求后处理完毕,重定向到前端新的页面(登录、绑定)并在URL中携带参数供前端做后续业务处理。


前端部分

生成微信登录二维码


   这里不使用跳转到微信自身的扫码授权页面,而是嵌入我们自身的登录页面,所以需要自行通过Js获取到微信的二维码数据,展示到我们的页面。


   参考文档:https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Wechat_Login.html


微信 wxLogin.js


   如果有其他修改需求,可以自行修改后传入自己的云存储,或者直接使用微信文档中的访问链接。


! function (a, b, c) {

   function d(a) {

       var c = "default";

       a.self_redirect === !0 ? c = "true" : a.self_redirect === !1 && (c = "false");

       var d = b.createElement("iframe"),

           e = "https://open.weixin.qq.com/connect/qrconnect?appid=" + a.appid + "&scope=" + a.scope +

           "&redirect_uri=" + a.redirect_uri + "&state=" + a.state + "&login_type=jssdk&self_redirect=" + c +

           '&styletype=' + (a.styletype || '') + '&sizetype=' + (a.sizetype || '') + '&bgcolor=' + (a.bgcolor || '') +

           '&rst=' + (a.rst || '');

       e += a.style ? "&style=" + a.style : "", e += a.href ? "&href=" + a.href : "", d.src = e, d.frameBorder = "0",

           d.allowTransparency = "true", d.scrolling = "no", d.width = "160px", d.height = "160px";

       var f = b.getElementById(a.id);

       f.innerHTML = "", f.appendChild(d)

   }

   a.WxLogin = d

}(window, document);


    



创建方法


/** 生成微信登录二维码 */

createWeChat() {

 const s = document.createElement("script");

 s.type = "text/javascript";

 // 微信提供的访问地址 或 自定义地址

 s.src = "https://h5.xxxxxx.com/h5/java-script/wxLogin.js";

 const wxElement = document.body.appendChild(s);

 wxElement.onload = function () {

   // 扫描二维码后重定向地址(这里重定向地址中的/test/可根据不同的环境进行不同的配置)

   const redirectUri = `http://auth.xxxxxx.com/test/callback/wx/login`

   // 微信登录实例JS对象

   const object = new WxLogin({

     self_redirect: false,

     // 页面中对应展示二维码的容器ID

     id: "wxMaContainer",

     appid: "xxxxxxxxxx",

     scope: "snsapi_login",

     redirect_uri: encodeURIComponent(redirectUri),

     // 若在业务中需要有多个判定参数 可以通过拼接的方式放在 state 中

     state: "login,0",

     style: "black",

     // 二维码样式及其它(关于样式自定义可在网上查阅到相关的实现)

     href: "data:text/css;base64,LmltcG93ZXJCb3ggLnFyY29kZSB7d2lkdGg6IDE0MHB4O30NCi5pbXBvd2VyQm94IC50aXRsZSB7ZGlzcGxheTogbm9uZTt9DQouaW1wb3dlckJveCAuaW5mbyB7ZGlzcGxheTogbm9uZTt9DQouc3RhdHVzX2ljb24ge2Rpc3BsYXk6IG5vbmV9DQouaW1wb3dlckJveCAuc3RhdHVzIHt0ZXh0LWFsaWduOiBjZW50ZXI7fQ=="

   });

 };

},


   



   关于重定向地址:当创建微信二维码时,前端会将上面的参数全部传给微信服务器,用户扫码确认后,会重定向到设置的redirectUri中,并且携带code参数,


后端部分

认证服务器Nginx配置


server {

   listen 80;

   server_name auth.xxxxxx.com;

   # 根据Host后的Path匹配到Test重定向到如下服务中

   location /test/ {

       rewrite ^/(.*) http://test.xxxxxx.com/$1 redirect;

   }

   location /prod/ {

       rewrite ^/(.*) http://creator.xxxxxx.com/$1 redirect;

   }

}


   


重定向到Java程序处理


仅展示主要逻辑代码,其他不予展示。


/**

* 微信登陆授权回调

*

* @author zhengshangjin

* created on 2021-03-31

*/

@GetMapping(value = "/callback/wx/login")

public void wxLogin(HttpServletRequest request, HttpServletResponse response) {

   oauthService.handleWxWebBack(request, response);

}


/**

* 处理微信回调业务情况

*

* @param request  请求

* @param response 响应

* @author zhengshangjin

* created on 2021-04-01

*/

@Override

public void handleWxWebBack(HttpServletRequest request, HttpServletResponse response) {

   String code = request.getParameter("code");

   String state = request.getParameter("state");

   log.info("handleWxWebBack code:{}, state:{}", code, state);

 

   if (StringUtils.isEmpty(code) || StringUtils.isEmpty(state)) {

       throw new BaseException("微信回调参数错误");

   }

 

   // 若在业务中需要有多个判定参数 可以通过拼接的方式放在 state 中

   String[] stateArr = state.split(",");

   if (stateArr.length < 2) {

       throw new BaseException("微信回调参数错误");

   }

   String type = stateArr[0];

   String userId = stateArr[1];

   log.info("handleWxWebBack type:{}, userId:{}", type, userId);

 

   // 绑定

   if (WX_BIND.equals(type)) {

       // 绑定状态

       int status = handleWxBind(code, userId);

       log.info("status:{}", status);

       try {

           // 重定向到前端绑定页面处理结果

           response.sendRedirect(wxBindNotify + "?status=" + status);

       } catch (IOException e) {

           log.error("ex msg:{}", e.getMessage());

       }

   }

   // 登录

   if (WX_LOGIN.equals(type)) {

       try {

           // 重定向到前端登录页面处理结果

           response.sendRedirect(wxLoginNotify + "?code=" + code);

       } catch (IOException e) {

           log.error("ex msg:{}", e.getMessage());

       }

   }

}


    


   至此,就完成了登录或者绑定微信的逻辑处理