常见的微信扫码登录有两种
这两种方式都需要提交企业资料认证和300元年费,有些想要学习或者自己的网站没有盈利的,其实不舍得花这个钱,特别是个人开发者,没有企业资料去做认证。
既然没法做企业认证,那我们就把矛头指向微信小程序了。
微信小程序无论是个人还是企业的,都开放了获取用户的基本信息,无须认证,不收费。而且,还提供了 1 个可以生成带参数的,数量暂无限制小程序码接口,所以我们就可以通过这个接口实现扫码登录了。
实现原理
登录页面从服务端获取一个带uuid参数的小程序码,然后创建一个websocket并带上这个uuid参数(用于网页端和小程序的通信绑定)
用户通过微信扫码授权后把登录code、用户信息和uuid参数提交到服务端
服务端根据登录code获取openId,然后在根据openId创建用户,最后生成user token广播给前端(通过uuid找到对应的soket链接并发送)
前端接收到token后,auth 登录,页面再重载一下,流程完毕
实战
获取小程序码
前端获取小程序码并创建websocket
import { Form, Tabs, Input, Button, Checkbox, Spin, Icon, message } from 'antd';
import React, { Component } from 'react';
import { FormComponentProps } from 'antd/es/form';
import { connect } from 'dva';
import { Link } from 'umi';
import { ConnectState, ConnectProps } from '@/models/connect';
import { getLoginCode } from './service';
import styles from './style.less';
const FormItem = Form.Item;
const { TabPane } = Tabs;
interface LoginProps extends ConnectProps, FormComponentProps {
submitting: boolean;
}
interface LoginState {
base64Img: string;
codeExpired: boolean;
codeLoading: boolean;
}
@connect(({ loading }: ConnectState) => ({
submitting: loading.effects['authLogin/login'],
}))
class Login extends Component {
static socketTimeout = 120000;
state: LoginState = {
base64Img: '',
codeExpired: false,
codeLoading: false,
};
ws: any;
timer: any;
componentDidMount() {
this.createWebSocket();
}
componentWillUnmount() {
clearTimeout(this.timer);
if (this.ws && this.ws.readyState === 1) {
this.ws.close();
}
}
createWebSocket = async () => {
clearTimeout(this.timer);
if (this.ws && this.ws.readyState === 1) {
this.ws.close();
}
this.setState({ codeExpired: false, codeLoading: true });
const { data: { base64_img: base64Img, token } } = await getLoginCode();
const socketUrl = `wss://${window.location.host}/wss?token=${token}`;
this.ws = new WebSocket(socketUrl);
this.ws.addEventListener('message', (e: any) => {
const { data: msg } = e;
const { event, data } = JSON.parse(msg);
/* eslint no-case-declarations:0 */
switch (event) {
case 'App\\Events\\WechatScanLogin':
const { token, permissions } = data;
// 获取到token后Auth登录
this.props.dispatch({
type: