谷粒学院——第十四章、微信扫码登录

准备工作

注册开发者资质

官网:https://open.weixin.qq.com/
image.png

尚硅谷分享

wx:
  open:
    # 微信开放平台 appid

    appid: wxed9954c01bb89b47

    # 微信开放平台 appsecret
    appsecret: a7482517235173ddb4083788de60b90e

    # 微信开放平台 重定向url(guli.shop需要在微信开放平台配置)
    redirecturl: http://guli.shop/api/ucenter/wx/callback

微信登陆流程

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

微信登陆实现

配置文件

在 service_ucenter 模块的配置文件 application.properties 中,填写微信ID,密钥和域名地址。修改端口(同时修改nginx中的端口)

# 服务端口(在这里需要修改端口)
server.port=8160
# 用于微信登陆
# 微信开放平台 appid
wx.open.app_id=wxed9954c01bb89b47
# 微信开放平台 appsecret
wx.open.app_secret=a7482517235173ddb4083788de60b90e
# 微信开放平台 重定向url
wx.open.redirect_url=http://localhost:8160/api/ucenter/wx/callback

创建 utils 包,然后创建类去读取配置文件中的值:

@Component
public class ConstantWxUtils implements InitializingBean {

    @Value("${wx.open.app_id}")
    private String appId;

    @Value("${wx.open.app_secret}")
    private String appSecret;

    @Value("${wx.open.redirect_url}")
    private String redirectUrl;

    public static String WX_OPEN_APP_ID;
    public static String WX_OPEN_APP_SECRET;
    public static String WX_OPEN_REDIRECT_URL;

    @Override
    public void afterPropertiesSet() {
        WX_OPEN_APP_ID = appId;
        WX_OPEN_APP_SECRET = appSecret;
        WX_OPEN_REDIRECT_URL = redirectUrl;
    }
}

生成扫描的二维码

直接请求微信提供的固定地址,然后向地址后面拼接参数。

在 service_ucenter 模块的 controller 层,创建类:

@CrossOrigin
@Controller
@RequestMapping("/api/ucenter/wx")
public class WxApiController {
    
    @ApiOperation("生成微信扫描的二维码")
    @GetMapping("/login")
    public String getWxCode() {
        // 微信开放平台授权baseUrl,%s是占位符
        String baseUrl = "https://open.weixin.qq.com/connect/qrconnect" +
                "?appid=%s" +
                "&redirect_uri=%s" +
                "&response_type=code" +
                "&scope=snsapi_login" +
                "&state=%s" +
                "#wechat_redirect";
        // 对 redirect_url 进行 URLEncoder 编码
        String redirectUrl = ConstantWxUtils.WX_OPEN_REDIRECT_URL;
        try {
            redirectUrl = URLEncoder.encode(redirectUrl, "utf-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        // 设置值
        String url = String.format(
                baseUrl,
                ConstantWxUtils.WX_OPEN_APP_ID,
                redirectUrl,
                "atguigu"
        );
        // 重定向
        return "redirect:" + url;
    }
}

image.png
启动项目,访问:http://localhost:8006/api/ucenter/wx/login,效果如下:
image.png

扫码之后获取信息

步骤图

image.png

image.png

工具类

需要先引入依赖,不过在一开始的时候,在 service 模块的 pom.xml 中已经引入过了,所以不必重新引入。
在 utils 包中复制提供好的工具类:
HttpClientUtils.java

controller 层

WxApiController 类添加方法:

@CrossOrigin
@Controller
@RequestMapping("/api/ucenter/wx")
public class WxApiController {

    @Autowired
    private MemberService memberService;

    @ApiOperation("生成微信扫描的二维码")
    @GetMapping("/login")
    public String getWxCode() {
        // 微信开放平台授权baseUrl,%s是占位符
        String baseUrl = "https://open.weixin.qq.com/connect/qrconnect" +
                "?appid=%s" +
                "&redirect_uri=%s" +
                "&response_type=code" +
                "&scope=snsapi_login" +
                "&state=%s" +
                "#wechat_redirect";
        // 对 redirect_url 进行 URLEncoder 编码
        String redirectUrl = ConstantWxUtils.WX_OPEN_REDIRECT_URL;
        try {
            redirectUrl = URLEncoder.encode(redirectUrl, "utf-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        // 设置值
        String url = String.format(
                baseUrl,
                ConstantWxUtils.WX_OPEN_APP_ID,
                redirectUrl,
                "atguigu"
        );
        // 重定向
        return "redirect:" + url;
    }

    // 获取扫描人信息,添加数据
    @ApiOperation("获取扫描人信息,添加数据")
    @GetMapping("callback")
    public String callback(String code, String state) {
        // 获取code值(临时票据),类似于验证码
        // 拿着 code 请求微信的固定地址,得到两个值 access_token 和 openid
        String baseAccessTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token" +
                "?appid=%s" +
                "&secret=%s" +
                "&code=%s" +
                "&grant_type=authorization_code";
        // 拼接三个参数:id、密钥和 code 值
        String accessTokenUrl = String.format(
                baseAccessTokenUrl,
                ConstantWxUtils.WX_OPEN_APP_ID,
                ConstantWxUtils.WX_OPEN_APP_SECRET,
                code
        );
        // 请求这个拼接好的地址,得到返回的两个值
        // 使用 httpclient 发送请求,得到返回结果
        String accessTokenInfo;
        try {
            accessTokenInfo = HttpClientUtils.get(accessTokenUrl);
        } catch (Exception e) {
            e.printStackTrace();
            throw new GuliException(20001, "登陆失败");
        }
        // 从 accessTokenInfo 中 取出来 access_token 和 openid 并转换成 map,根据 key 获取对应值
        Gson gson = new Gson();
        Map mapAccessToken = gson.fromJson(accessTokenInfo, HashMap.class);
        String access_token = (String) mapAccessToken.get("access_token");
        String openid = (String) mapAccessToken.get("openid");
        // 扫码人的信息添加到数据库中
        // 根据 openid 判断数据库中是否存在相同的微信信息
        UcenterMember member = memberService.getOpenIdMember(openid);
        if (member == null) {
            // 拿着得到的 access_token 和 openid 再去请求微信提供的地址,获得扫码人的信息
            String baseUserInfoUrl = "https://api.weixin.qq.com/sns/userinfo" +
                    "?access_token=%s" +
                    "&openid=%s";
            // 拼接两个参数
            String userInfoUrl = String.format(baseUserInfoUrl, access_token, openid);
            // 发送请求
            String userInfo;
            try {
                userInfo = HttpClientUtils.get(userInfoUrl);
            } catch (Exception e) {
                e.printStackTrace();
                throw new GuliException(20001, "登陆失败");
            }
            // 从 userInfo 中获取扫码人的信息
            Map userInfoMap = gson.fromJson(userInfo, HashMap.class);
            String nickname = (String) userInfoMap.get("nickname"); // 昵称
            String headimgurl = (String) userInfoMap.get("headimgurl"); // 头像
            member = new UcenterMember();
            member.setOpenid(openid);
            member.setNickname(nickname);
            member.setAvatar(headimgurl);
            memberService.save(member);
        }
        // 使用 JWT 根据 mapper 对象生成 token 字符串
        String jwtToken = JwtUtils.getJwtToken(member.getId(), member.getNickname());
        return "redirect:http://localhost:3000?token=" + jwtToken;
    }
}

service 层

MemberService 类添加:

    // 根据 openid 判断
    UcenterMember getOpenIdMember(String openid);

实现类添加:

    // 根据 openid 判断
    @Override
    public UcenterMember getOpenIdMember(String openid) {
        QueryWrapper<UcenterMember> wrapper = new QueryWrapper<>();
        wrapper.eq("openid", openid);
        return baseMapper.selectOne(wrapper);
    }

前端页面显示登陆信息

default.vue

修改 layouts/default.vue

<script>
import '~/assets/css/reset.css'
import '~/assets/css/theme.css'
import '~/assets/css/global.css'
import '~/assets/css/web.css'
import cookie from 'js-cookie'
import loginApi from '@/api/login'

export default {
  data() {
    return {
      token: '',
      loginInfo: {
        id: '',
        age: '',
        avatar: '',
        mobile: '',
        nickname: '',
        sex: ''
      }
    }
  },
  created() {
    // 获取路径中的 token 值
    this.token = this.$route.query.token
    if (this.token) {
      // 如果能取到就用微信扫码登陆
      this.wxLogin()
    }
    this.showInfo()
  },
  methods: {
    // 微信登陆显示的方法
    wxLogin() {
      // 把 token 放到 cookie
      cookie.set('guli_token', this.token, { domain: 'localhost' })
      cookie.set('guli_ucenter', '', { domain: 'localhost' })
      // 调用接口,根据 token 值获取用户信息
      loginApi.getLoginUserInfo().then(response => {
        this.loginInfo = response.data.data.userInfo
        cookie.set('guli_ucenter', this.loginInfo, { domain: 'localhost' })
      })
    },
    // 退出的方法
    logout() {
      // 清空cookie值
      cookie.set('guli_token', '', { domain: 'localhost' })
      cookie.set('guli_ucenter', '', { domain: 'localhost' })
      // 回到首页面
      window.location.href = '/'
    },
    // 创建方法从cookie中获取信息
    showInfo() {
      // 从cookie中获取信息
      var userStr = cookie.get('guli_ucenter')
      // 转字符串转换成json对象(js对象)
      if (userStr) {
        this.loginInfo = JSON.parse(userStr)
      }
    }
  }
}
</script>

测试

访问:http://localhost:8160/api/ucenter/wx/login

微信扫码登陆后,地址栏返回:http://localhost:3000/?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJndWxpLXVzZXIiLCJpYXQiOjE2MjExNTUzMTgsImV4cCI6MTYyMTI0MTcxOCwiaWQiOiIxMzkzODQ3NTQ3MDc1Nzg4ODAyIiwibmlja25hbWUiOiJKeXVua2FpIn0.-IdNv8SCo3L39BQkxDxRqlALst2JnXe3wLbTHX-dOYk

查看数据库中增加了一条信息:
image.png

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

肉丝不切片

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值