​简短回顾一下网页端的流程,总的来说网页端的职责有三:

  1. 生成一个随机字符作为鉴权会话的临时Token,
  2. 生成一个小程序码, Token作为参数固化于小程序码当中
  3. 监控整个鉴权过程状态,一旦状态变为AUTHORIZED(已授权)则获取小程序登录凭证code。调用ExternalAuthenticate完成登录。

上一章,我们介绍了服务端的开发,这次我们需要调用GetACode,GetToken,分别获取小程序码,和获取当前状态

首先使用vue-cli创建一个web项目,命名为mp-auth

vue create mp-auth

新建ajaxRequest.ts,创建request对象,这一对象将利用axios库发送带有访问凭证的Header的请求

这里使用js-cookie库获取cookie中的访问凭证,并添加到Header中

import Cookies from "js-cookie";
import axios, { CancelTokenSource } from 'axios'
//发送网络请求
const tokenKey = "main_token";
const getToken = () => Cookies.get(tokenKey); export const request = async (url: string, methods, data: any, onProgress?: (e) => void, cancelToken?: CancelTokenSource) => {
let token = null
let timeout = 3000;
if (cancelToken) {
token = cancelToken.token
timeout = 0;
} const service = axios.create()
service.interceptors.request.use(
(config) => {
const token = getToken();
// Add X-Access-Token header to every request, you can add other custom headers here
if (token) {
config.headers['X-XSRF-TOKEN'] = token
config.headers['Authorization'] = 'Bearer ' + token
}
return config
},
(error) => {
Promise.reject(error)
}
) const re = await service.request({
url: url,
method: methods,
data: data,
cancelToken: token,
timeout: timeout,
onUploadProgress: function (progressEvent) { //原生获取上传进度的事件
if (progressEvent.lengthComputable) {
if (onProgress) {
onProgress(progressEvent);
}
}
},
})
return re as any;
} ///获得取消令牌
export const getCancelToken = () => {
const source = axios.CancelToken.source();
return source;
}

回到App.vue

我们按照网页端这个三个职责的顺序,分步骤完成代码

生成Token

首先建立两个变量,存储当前的Token和状态枚举值

export default {
name: "App",
data: () => {
return {
wechatMiniappLoginToken: null,
wechatMiniappLoginStatus: "WAIT",
};
},

methods中建立getToken函数,这里使用8位随机数作为token值

  methods: {
getToken() {
if (this.wechatMiniappLoginToken == null) {
var date = new Date();
var token = `${(Math.random() * 100000000)
.toFixed(0)
.toString()
.padEnd(8, "0")}`;
this.wechatMiniappLoginToken = token;
}
return this.wechatMiniappLoginToken;
}
}

生成小程序码

Html部分,插入一个图片,将token传入scene参数

<img :src="`${prefix}/MiniProgram/GetACode?scene=${getToken()}&page=${miniappPage}&mode=content`"/>

Prefix是你的服务地址前缀

prefix: "https://localhost:44311/api/services/app"

page为小程序中鉴权页面的路径,需注意的是在小程序未发布时无法跳转至页面,报错41030,若要使用扫码来跳转指定页面,小程序需要先发布

miniappPage: "pages/login/index"

监控整个鉴权过程状态

首先需要一个函数,根据当前的Token获取当前鉴权状态,并且不断循环这一操作,这里编写start函数,并以每1秒钟轮询状态,代码如下:

   start() {
clearInterval(this.timerId);
this.timerId = setInterval(async () => {
if (!this.loading) {
this.loading = true; await request(
`${this.prefix}/MiniProgram/GetToken?token=${this.wechatMiniappLoginToken}`,
"get",
null
)
}
}, 1000);
},

在页面开始函数代码Created中调用这一函数

  created: function () {
this.start();
},

接下来处理轮询结果,如果没有拿到值,说明Token已过期,wechatMiniappLoginStatus状态为"EXPIRED"

          await request(
`${this.prefix}/MiniProgram/GetToken?token=${this.wechatMiniappLoginToken}`,
"get",
null
)
.then(async (re) => {
if (re.data.result == null) {
this.wechatMiniappLoginStatus = "EXPIRED";
this.wechatMiniappLoginToken = null;
this.loading = false;
}

注意:

在后端项目的MiniProgramAppService.cs中,我们定义的

TokenCacheDuration为5分钟,表明二维码的有效时间为5分钟。

public static TimeSpan TokenCacheDuration = TimeSpan.FromMinutes(5);

相应的Token为Expired时,将wechatMiniappLoginToken置空,这一属性变动vue会通知img的src值变动而刷新小程序码,同时获取新的Token值赋值给wechatMiniappLoginToken,这也是刷新小程序码的逻辑

this.wechatMiniappLoginToken = null;

这样能以简单方式,实现二维码刷新功能。

界面中新建一个刷新小程序码的按钮:

      <el-button
v-if="wechatMiniappLoginToken != null"
type="primary"
size="medium"
@click="wechatMiniappLoginToken = null"
>刷新
</el-button>

编写一个externalLogin方法,在用于获取Code后,调用后端第三方登录接口,获取访问凭证存储于Cookie中

async externalLogin(userInfo: {
authProvider: string;
providerKey: string;
providerAccessCode: string;
}) {
let authProvider = userInfo.authProvider;
let providerKey = userInfo.providerKey;
let providerAccessCode = userInfo.providerAccessCode; await request(
`https://localhost:44311/api/TokenAuth/ExternalAuthenticate`,
"post",
{
authProvider,
providerKey,
providerAccessCode,
}
).then(async (res) => {
var data = res.data.result;
setToken(data.accessToken);
});
},

定义setToken函数,使用js-cookie库将访问凭证写入浏览器cookie中

const tokenKey = "main_token";
const setToken = (token: string) => Cookies.set(tokenKey, token);

在此之前我们需写一个参数传递对象,为了保留一定的扩展能力,data中我们定义loginExternalForms,已经实现的微信小程序登录,则对应的authProvider值为“WeChatAuthProvider”,providerAccessCode则为生成的Token值

      loginExternalForms: {
WeChat: {
authProvider: "WeChatAuthProvider",
providerKey: "default",
providerAccessCode: "",
},
},

接下来包装externalLogin方法,在调用完成前后做一些操作,比如登录成功后,将调afterLoginSuccess方法

为了保留一定的扩展能力,handleExternalLogin函数中我们保留参数authProvider,已实现的微信小程序登录handleWxLogin函数调用时传递参数"WeChat"

    async handleExternalLogin(authProvider) {
// (this.$refs.baseForm as any).validate(async (valid) => {
// if (valid == null) {
var currentForms = this.loginExternalForms[authProvider]; this.loading = true;
return await this.ExternalLogin(currentForms).then(async (re) => {
return await request(
`${this.prefix}/User/GetCurrentUser`,
"get",
null
).then(async (re) => {
var result = re.data.result as any;
return await this.afterLoginSuccess(result);
});
});
}, async handleWxLogin(providerAccessCode) {
this.loginExternalForms.WeChat.providerAccessCode = providerAccessCode;
return await this.handleExternalLogin("WeChat");
},

afterLoginSuccess函数用于登录成功后的逻辑,停止计时器,并跳转页面,本实例仅做弹窗提示

    successMessage(value = "执行成功") {
this.$notify({
title: "成功",
message: value,
type: "success",
});
}, async afterLoginSuccess(userinfo) {
clearInterval(this.timerId);
this.successMessage("登录成功");
this.userInfo = userinfo;
},

继续编写start函数

如果拿到的token至不为空,则传递值给wechatMiniappLoginStatus,当wechatMiniappLoginStatus状态为"AUTHORIZED"时调用handleWxLogin函数:

              if (re.data.result == null) {
this.wechatMiniappLoginStatus = "EXPIRED";
this.wechatMiniappLoginToken = null;
this.loading = false;
} else {
var result = re.data.result;
this.wechatMiniappLoginStatus = result.status;
if (
this.wechatMiniappLoginStatus == "AUTHORIZED" &&
result.providerAccessCode != null
) {
await this.handleWxLogin(result.providerAccessCode)
.then(() => {
this.wechatMiniappLoginToken = null;
this.loading = false;
})
.catch((e) => {
this.wechatMiniappLoginToken = null;
this.loading = false;
clearInterval(this.timerId);
});
} else {
this.loading = false;
}
}

接下来简单编写一个界面,

界面将清晰的反映wechatMiniappLoginStatus各个状态时对应的UI交互:

WAIT(等待扫码):

ACCESSED(已扫码):

ACCESSED(已扫码):

完整的Html代码如下:

<template>
<div id="app">
<!-- <img alt="Vue logo" src="./assets/logo.png" />
<HelloWorld msg="Welcome to Your Vue.js App" /> -->
<div style="height: 450px">
<div v-if="wechatMiniappLoginStatus == 'ACCESSED'">
<el-result
icon="info"
title="已扫码"
subTitle="请在小程序上根据提示进行操作"
>
</el-result>
</div> <div v-else-if="wechatMiniappLoginStatus == 'AUTHORIZED'">
<el-result
icon="success"
title="已授权"
:subTitle="loading ? '请稍候..' : '正在使用微信账号登录系统'"
>
</el-result>
</div>
<div v-else class="center">
<img
:src="`${prefix}/MiniProgram/GetACode?scene=${getToken()}&page=${miniappPage}&mode=content`"
/>
</div>
</div>
<div class="center">
<el-button
v-if="wechatMiniappLoginToken != null"
type="primary"
size="medium"
@click="wechatMiniappLoginToken = null"
>刷新</el-button
>
</div>
<div class="center">
<span>{{ userInfo }}</span>
</div>
</div>
</template>

至此我们已完成网页端的开发工作

使用 Abp.Zero 搭建第三方登录模块(三):网页端开发的更多相关文章

  1. 使用 Abp.Zero 搭建第三方登录模块(一):原理篇

    ​第三方登录是基于用户在第三方平台上(如微信,QQ, 百度)已有的账号来快速完成系统的登录.注册-登录等功能. 微信的鉴权 以微信的鉴权为例: 假如你的网站有一个扫码登录的功能,会弹出一个由微信提供的 ...

  2. 第四百零四节,python网站第三方登录,social-auth-app-django模块,

    第四百零四节,python网站第三方登录,social-auth-app-django模块, social-auth-app-django模块是专门用于Django的第三方登录OAuth2协议模块 目 ...

  3. 3. ABP .NETCore 添加企业微信第三方登录

    1.企业微信登录步骤 1.获取企业微信Token 官方文档:https://work.weixin.qq.com/api/doc#90000/90135/91039 2.通过Token 与前端传的Co ...

  4. QQ第三方登录

    QQ第三方登录 在Android应用程序的开发过程中,很多时候需要加入用户登录/注册模块.除了自己动手设计登录界面并实现相应功能外,现在还可以借助百度.腾讯等开发者平台提供的第三方账号登录模块.最近研 ...

  5. CI框架 QQ接口(第三方登录接口PHP版)

    本帖内容较多,大部分都是源码,要修改的地方只有一个,其他只要复制过去,就可以完美运行.本帖主要针对CI框架,不用下载SDK,按我下面的步骤,建文件,复制代码就可以了.10分钟不要,接口就可完成.第一步 ...

  6. QQ登录接口(第三方登录接口)

    CI框架 QQ接口(第三方登录接口PHP版) 本帖内容较多,大部分都是源码,要修改的地方只有一个,其他只要复制过去,就可以完美运行.本帖主要针对CI框架,不用下载SDK,按我下面的步骤,建文件,复制代 ...

  7. 从零开始用 Flask 搭建一个网站(三)

    从零开始用 Flask 搭建一个网站(二) 介绍了有关于数据库的运用,接下来我们在完善一下数据在前端以及前端到后端之间的交互.本节涉及到前端,因此也会讲解一下 jinja2 模板.jQuery.aja ...

  8. Unity利用Share SDK实现QQ、微信及微博第三方登录及定制内容分享(附代码)

    最近因为公司的项目需要添加一些实用性的功能,需要添加第三方登录及分享,采用的是Mob的SDK,可以先到其官网下载对应的SDK 点击这里,为了方便后期进行数据统计和分析,所以可以先添加一个应用,添加成功 ...

  9. 使用OAuth2.0协议的github、QQ、weibo第三方登录接入总结

    目录 第三方接入总结 OAuth2.0介绍 github OAuth2.0登录接入 国内第三方应用商SDK使用 微博SDK 腾讯QQ SDK passport.js插件使用 安装 相关中间件.路由 返 ...

随机推荐

  1. 代码源 每日一题 分割 洛谷 P6033合并果子

    ​ 题目链接:切割 - 题目 - Daimayuan Online Judge 数据加强版链接: [NOIP2004 提高组] 合并果子 加强版 - 洛谷 题目描述 有一个长度为 ∑ai 的木板,需要 ...

  2. centos 7.0 下安装FFmpeg软件 过程

    这几天由于需要编写一个语音识别功能,用到了百度语音识别接口,从web端或小程序端传上来的音频文件是aac或者mp3或者wav格式的,需要使用FFmpeg进行格式转换,以符合百度api的要求. 安装FF ...

  3. 2003031121——浦娟——Python数据分析第七周作业——MySQL的安装及使用

    项目 要求 课程班级博客链接 20级数据班(本) 作业要求链接 Python第七周作业 博客名称 2003031121--浦娟--Python数据分析第七周作业--MySQL的安装及使用 要求 每道题 ...

  4. CSAPP 之 BombLab 详解

    前言 本篇博客将会展示 CSAPP 之 BombLab 的拆弹过程,粉碎 Dr.Evil 的邪恶阴谋.Dr.Evil 的替身,杀手皇后,总共设置了 6 个炸弹,每个炸弹对应一串字符串,如果字符串错误, ...

  5. SpringBoot项目使用jasypt加解密

    Jasypt 是一个 Java 库,它允许开发者以最小的努力为他 / 她的项目添加基本的加密功能,而且不需要对密码学的工作原理有深刻的了解. 一.添加依赖 <dependency> < ...

  6. Linux磁盘空间查看及空间满的处理

    问题 在部署应用到测试环境的时候,有些文件同步出错,最后定位到测试服务器空间满了. 解决 查看磁盘空间还剩多少空间 df -h 查看根目录下每个目录占用空间大小 du --max-depth=1 -h ...

  7. 【单片机】CH32V103v8t6开发板调试笔记

    一.开发板样式和资源 找官网的商务申请了一块开发板,打算试一下串口打印程序测试,发现网上关于这个板子的相关资料特别少,为方便后来人,就顺便记录一下,板子资源如下图所示. 板子芯片的引脚排布图 二.使用 ...

  8. 简历应该怎么写,HR看一篇简历仅需要5秒吗,简历模板大全

    哈喽!大家好,我是小奇,一位热爱分享的程序员 小奇打算以轻松幽默的对话方式来分享一些技术,如果你觉得通过小奇的文章学到了东西,那就给小奇一个赞吧 文章持续更新 一.前言 最近有很多小伙伴问奇哥,说奇哥 ...

  9. 多态——JavaSE基础

    多态 同一个方法可以根据对象的不同采取不同的动作 一个对象的实际类型是确定的,但可以指向对象的引用类型有很多 基本条件: 有继承关系 子类重写父类方法 父类引用指向子类对象Father f1 = ne ...

  10. linux基本命令续(杂糅和转)

    此处使用CP 命令复制/etc/profile和/etc/init.d/network到家目录下,当然也可以指定其他目录如./ 根目录等. 在2提示处,如果输错了文字,可以ctrl+backspace ...