前后端分离下微信登录高并发问题

前后端分离 微信登录 高并发问题

具体描述

前端发起请求 ->(改进 插入 state: uuid)
后端拉起二维码 ->
用户确认 ->
微信回调 ->
自己的处理逻辑(将用户信息 存入 token (这里使用的是jwt)) ->
重定向到 (首页)等等
(改进 前端再次访问 后端 获取 token)

这里出现的问题

如何将 token 提供给前端

因为是前后端分离 直接 return 会原路返回,不能跳转的自己的界面

1.使用ThreadLocal,由前端主动发起请求获取 token

private ThreadLocal token = new ThreadLocal();
但是 springboot 中 controller 是单例多线程的
而 ThreadLocal 是为 当前线程赋值, 前端来取是另一个线程,故取不到

2.存入cookie、session

cookie 可以被用户禁用
session 在app上没有这种概念
故不可取

3.最开始是想,在回调的时候响应的时候直接 将token由response来设置头信息设置上去,但随后 redirect 重定向 (但 这里 重定向 是 网页自动完成 (token在上一个 现在重定向是另一个获取不到)(又因为是自动完成的重定向 故获取不到(这里是本人觉得获取不到,因为不太会))

没实现

成功解决的方案

在用户 点击 微信登录 拉起 后端 这里将 拉起微信二维码 的 参数
appidredirect_uriscope 传给前端由前端实现二维码的拉起
这里加入 一个操作
获取一个uuid 将 uuid 也传给前端 前端接收 接收名为 state
拉起的时候将 state 传入 微信二维码 这样 回调 访问后端的时候
将解析出来的用户信息 存入 token (这里用的 jwt )
以 state为key ----- token为 value 存入 redis

回调完成后 重定向 到 首页 ,
此时来完成轮询 (通过判断 来 携带 state 访问 后端 )
由state (key) 获取 redis 中的 token (value)
由此来获取用户信息

  1. 用户点击微信登录
   @GetMapping("/login/wechat")
 // Result 是自定义的 统一返回 结果 map 结构
   public Result wxLogin(HttpServletResponse response) throws IOException {
       String uuId = UUID.randomUUID().toString().replace("-", "");
       System.out.println("state = " + uuId);
       return Result.ok()
       .setData("state", uuId)
       .setDate("scope",wechatConfig.getScope())
       .setData("appid", wechatConfig.getAppid())
       .setData("redirect_uri", wechatConfig.getRedirectUri());
   }
  1. 前端处理 二维码 参数
 loginWx() {
      this.axios
          .get("http://localhost:9000/user/user/login/wechat")
          .then((result) => {
            console.log(result)
            document.getElementById("loginForm").style.display = "none";
            // 显示二维码的容器
            document.getElementById("wxLoginForm").style.display = "block";
            // const url = result.data.data.item;
            this.state = result.data.data.state;
            this.appid = result.data.data.appid;
            this.scope = result.data.data.scope;
            this.redirect_uri = result.data.data.redirect_uri;
            localStorage.setItem("state", this.state);
            this.$nextTick(function () {
              this.createCode();
            });
          })

将这些参数接收后 拼接完成地址 由前端打开(即二维码窗口)同时是由前端控制,可以设置 样式

    createCode() {
      console.log(this.state)
      var obj = new WxLogin({
        id: "wxLoginForm", // 挂载点,二维码的容器
        appid: this.appid, // 应用唯一标识,在微信开放平台提交应用审核通过后获得
        scope: this.scope, // 应用授权作用域,网页应用目前仅填写snsapi_login即可
        redirect_uri: this.redirect_uri,  //重定向地址,(回调地址)
        state: this.state,
        href: "data:text/css;base64,LmltcG93ZXJCb3ggLnFyY29kZSB7d2lkdGg6IDIwMHB4O30NCi5pbXBvd2VyQm94IC50aXRsZSB7ZGlzcGxheTogbm9uZTt9DQouaW1wb3dlckJveCAuaW5mbyB7d2lkdGg6IDIwMHB4O30NCi5zdGF0dXNfaWNvbiB7ZGlzcGxheTogbm9uZX1jcw0KLmltcG93ZXJCb3ggLnN0YXR1cyB7dGV4dC1hbGlnbjogY2VudGVyO30=" // 加载修饰二维码的css样式
      });
    },
    !(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.sandbox = "allow-scripts allow-top-navigation allow-same-origin"), // 允许多种请求
            (d.scrolling = "no"),
            (d.width = "300px"),
            (d.height = "400px");
        var f = b.getElementById(a.id);
        (f.innerHTML = ""), f.appendChild(d);
      }

      a.WxLogin = d;
    })(window, document);
  1. 此处省略 回调 获取 用户信息 由jwt加密 放入 token

重定向前端
response.sendRedirect(wechatConfig.getSuccessUrl());

  1. 由state获取token
    @GetMapping("checkWxStatus")
    public Result checkWxStatus(String state) {
        Object o = redisUtils.getValue(state);
        System.out.println("state = " + state);
        redisUtils.delete(state);
        return Result.ok().setData("item", o.toString());
    }
  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值