前端笔记_OAuth规则机制下实现个人站点接入qq三方登录

文章目录

    • ⭐前言
    • ⭐qq三方登录流程
      • 💖qq互联中心创建网页应用
      • 💖配置回调地址redirect_uri
      • 💖流程分析
    • ⭐思路分解
    • ⭐技术选型+实现
      • 💖技术选型:
      • 💖实现
    • ⭐结束

yma16-logo

⭐前言

大家好,我是yma16,本文分享OAuth规则机制下实现个人站点接入qq三方登录。
oauth授权

OAuth是一种授权机制,用于允许用户(资源所有者)向第三方应用程序授予有限的访问权限,而不必将凭证直接提供给第三方应用程序。OAuth的目的是为了保护用户的私密数据,如社交媒体帐户、云存储、银行帐户等。它通过一个流程,将用户授权给第三方应用程序访问用户的资源,而不需要第三方应用程序获得用户的凭证信息。这样做可以减少用户数据泄露的风险。OAuth是一个开放的标准,由OAuth工作组维护,并得到许多组织的支持和使用。

oauth的发展

OAuth协议的发展历史可以追溯到2004年,当时美国国防部提出了一个名为“OpenID Connect”的开放式身份认证和授权标准,旨在解决Web 2.0中的身份认证和授权问题。OAuth1.0于2005年被RFC 5849正式标准化,OAuth2.0于2011年被RFC 6749正式标准化 。

OAuth1.0的主要特点是将用户的认证信息(如用户名和密码)与第三方应用的请求分离开来,从而提高了安全性。
OAuth2.0则在OAuth1.0基础上进一步改进,增加了更多的功能和灵活性,如授权码模式、隐式模式、密码模式等 。

效果
在个人站点实现三方qq登录
链接直达:https://yongma16.xyz
唤起三方登录urlurl-login

获取qq用户账号头像和openid登入
openid-qq

⭐qq三方登录流程

前提条件: 存在可访问的网站,在qq互联中心创建应用审核
友情提示:网站不可使用外部cdn,可导致审核人员查看白屏而失败

💖qq互联中心创建网页应用

填写域名资料,提交审核
openid-app

💖配置回调地址redirect_uri

回调地址是用户使用qq登录之后调整的地址会携带code和state的参数

💖流程分析

  1. 唤起qq授权登录url
  2. 登录qq成功获取code
  3. 通过code去换取access_token
  4. 通过access_token去换取openid
  5. 通过access_token和openid去换取userinfo

processs-qq-third-login

⭐思路分解

1.登录页面新开窗口的auth授权qq页面
2.自定义node服务去渲染回调redirect_uri,成功登录时回传url上的参数给父页面,然后用定时器关闭页面
3. 拿到code后去换取token
4. 拿到token去换取openid
5. 拿到openid去换取userinfo
6. 使用openid去注册网站用户,显示nickname网名

⭐技术选型+实现

💖技术选型:

后端:
node
前端:
vue2
后端node封装接口

💖实现

node封装接口:
api.js

const request = require('request');

const loginUrl='https://graph.qq.com/oauth2.0/authorize'
const codeToTokenUrl='https://graph.qq.com/oauth2.0/token'
const openIdUrl='https://graph.qq.com/oauth2.0/me'
const userInfoUrl='https://graph.qq.com/user/get_user_info'
const appid=自己的appid
const appKey=自己的appkey
const redirect_uri=自己的回调地址

const getAuthUrl=(state)=>{
    return new Promise(resolve=>{
        const params={
            response_type:'code',
            client_id:appid,
            redirect_uri:encodeURI(redirect_uri),
            state:state?state:'myblog',
        };
        const path=Object.keys(params).forEach(key=>{
            return `${key}=${params[key]}`
        }).join('&')
        const url=loginUrl+'?'+path
        resolve(url)
    })
};

const getToken=(code)=>{
    return new Promise(async ( resolve ,reject)=> {
            request(
                {
                    method: 'GET'
                    , uri: codeToTokenUrl,
                    qs: {
                        grant_type: 'authorization_code',
                        client_id: appid,
                        client_secret: appKey,
                        code: code,
                        redirect_uri: encodeURI(redirect_uri),
                        fmt: 'json'
                    }
                }, function (error, response) {
                    if (!error && response.statusCode === 200) {
                        resolve(response)
                    } else {
                        console.log("error",error);
                        reject(reject)
                    }
                })
        }
    )
};

const getOpenId=(access_token)=>{
    return new Promise(async ( resolve ,reject)=> {
            request(
                {
                    method: 'GET'
                    , uri: openIdUrl,
                    qs: {
                        access_token:access_token,
                        fmt: 'json'
                    }
                }, function (error, response) {
                    if (!error && response.statusCode === 200) {
                        resolve(response)
                    } else {
                        reject(error)
                    }
                })
        }
    )
};

const getUserInfo=(access_token,openId)=>{
    return new Promise(async ( resolve ,reject)=> {
            request(
                {
                    method: 'GET'
                    , uri: userInfoUrl,
                    qs: {
                        access_token:access_token,
                        oauth_consumer_key:appid,
                        openid:openId,
                        fmt: 'json'
                    }
                }, function (error, response) {
                    if (!error && response.statusCode === 200) {
                        resolve(response)
                    } else {
                        reject(error)
                    }
                })
        }
    )
}

module.exports={
    getAuthUrl,
    getToken,
    getOpenId,
    getUserInfo
};

node开放接口:

const hostname = 'localhost';
const port = 6677;

const express = require("express");

const {getAuthUrl,getToken,getOpenId,getUserInfo}=require('./service/api.js');
const app = express();

app.listen(port,hostname, () => {
    console.log(`Server running at http://${hostname}:${port}/`);
});
// server your css as static
app.use(express.static(__dirname));
// views
const thirdLoginDir='/views/thirdLogin/';
app.get("/getAuthUrl",async (req, res) => {
    try{
        const {query}=req
        const {state}=query
        const url=await getAuthUrl(state)
        res.json({
            code:authRes.statusCode,
            data:url,
        })
    }
    catch (e) {
        res.json({
            code:0,
            msg:e
        })
    }
});

app.get("/getToken",async (req, res) => {
    try{
        const {query}=req
        const {code}=query
        console.log('code',code)
        const tokenRsponse=await getToken(code)
        res.json({
            code:tokenRsponse.statusCode,
            data:JSON.parse(tokenRsponse.body),
        })
    }
    catch (e) {
        res.json({
            code:0,
            msg:e
        })
    }
});

app.get("/getOpenId",async (req, res) => {
    try{
        const {query}=req
        const {access_token}=query
        console.log('access_token',access_token)
        const openidRes=await getOpenId(access_token)
        res.json({
            code:openidRes.statusCode,
            data:JSON.parse(openidRes.body)
        })
    }
    catch (e) {
        res.json({
            code:0,
            msg:e
        })
    }
});

app.get("/quickGetOpenId",async (req, res) => {
    try{
        const {query}=req
        const {code}=query
        console.log('code',code)
        const tokenRsponse=await getToken(code)
        const tokenBody=JSON.parse(tokenRsponse.body)
        const {access_token}=tokenBody
        const openIdRsponse=await getOpenId(access_token)
        res.json({
            code:tokenRsponse.statusCode,
            data:JSON.parse(openIdRsponse.body)
        })
    }
    catch (e) {
        res.json({
            code:0,
            msg:e
        })
    }
});

app.get("/getUserInfo",async (req, res) => {
    try{
        const {query}=req
        const {access_token,openId}=query
        console.log('access_token openId',access_token,openId)
        const userInfoRes=await getUserInfo(access_token,openId)
        res.json({
            code:userInfoRes.statusCode,
            data:JSON.parse(userInfoRes.body)
        })
    }
    catch (e) {
        res.json({
            code:0,
            msg:e
        })
    }
});

app.get("/qq_login_callback", (req, res) => {
    res.sendFile(__dirname + thirdLoginDir+"qqLoginCallback.html");
});
app.get("/azure_login_callback", (req, res) => {
    res.sendFile(__dirname + thirdLoginDir+"azureLoginCallback.html");
});

回调html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>qqLoginCallback</title>
</head>
<body>
qq login success!
<script type="application/javascript">
    function init() {
        console.log('qq success login')
        console.log('window.location.href',window.location.href)
        const href=window.location.href
        const data={}
        const urlArray=href.split('?')
        const urlLength=urlArray.length
        if(urlLength>1){
            urlArray[urlLength-1].split('&').forEach(item=>{
                const itemArray=item.split('=')
                const key=itemArray[0]
                const value=itemArray[1]
                data[key]=value
            })
        }
        if(window.opener)
        {
            //发送data
            window.opener.postMessage(data,'*')
            //关闭
            setTimeout(()=>{
                window.close()
            },1000)
        }
    }
    window.onload=init
</script>
</body>
</html>

vue前端qq登录的调用:

		async qqLogin () {
            try {
                const that = this
                // qq
                const res = await that.$axios
                    .post('/third-login/getAuthUrl')
                console.log('res', res)
                if (res.data && res.data.data) {
                    const resData = res.data.data
                    console.log('resData', resData)
                    if (resData ) {
                        let url = resData 
                        console.log('url', url)
                        const openHandle = window.open(url, 'width:800px;height:700px', '_black')
                        console.log('openHandle', openHandle)
                        window.onmessage = async (res) => {
                            const {origin, data} = res
                            if (origin.includes('yongma16.xyz')) {
                                const {code, state} = data
                                console.log('code state', code, state)
                                that.thirdLoginConfig.qCode = code
                                that.thirdLoginConfig.qState = state
                                const tokenRes = await that.getAccessToken(code)
                                console.log('tokenRes', tokenRes)
                            }
                        }
                    }
                }
                return new Promise(resolve => {
                    resolve(true)
                })
            } catch (e) {
                return new Promise((resolve, reject) => {
                    reject(e)
                })
            }
        },
        async getAccessToken (code) {
            try {
                const tokenUrl = '/third-login/getToken'
                const params = {
                    code
                }
                const tokenRes = await this.$axios.get(tokenUrl, {params})

                console.log('tokenRes', tokenRes)
                if (tokenRes) {
                    const {access_token, expires_in, refresh_token} = tokenRes.data.data
                    if (access_token) {
                        this.thirdLoginConfig.qToken = access_token
                        await this.getOpenId(access_token)
                    }
                }
            } catch (e) {
                console.log('token error', e)
            }
        },
        async getOpenId (token) {
            try {
                const tokenUrl = '/third-login/getOpenId'
                const params = {
                    access_token: token
                }
                const openIdRes = await this.$axios.get(tokenUrl, {params})
                console.log('openIdRes', openIdRes)
                if (openIdRes) {
                    const {openid} = openIdRes.data.data
                    if (openid) {
                        this.thirdLoginConfig.qOpenid = openid
                        await this.getQUserinfo(this.thirdLoginConfig.qToken, openid)
                    }
                }
            } catch (e) {
                console.log('token error', e)
            }
        },
        async getQUserinfo (token, openId) {
            try {
                const userInfoUrl = '/third-login/getUserInfo'
                const params = {
                    access_token: token,
                    openId: openId
                }
                const userRes = await this.$axios.get(userInfoUrl, {params})
                if (userRes) {
                    this.thirdLoginConfig.qUserInfo = userRes.data.data
                    this.registerThirdLogin()
                }
                console.log('userRes', userRes)
            } catch (e) {
                console.log('token error', e)
            }
        }

效果:

quick_qq_login

⭐结束

本文分享到这结束,如有错误或者不足之处欢迎指出!
sky-night

👍 点赞,是我创作的动力!
⭐️ 收藏,是我努力的方向!
✏️ 评论,是我进步的财富!
💖 感谢你的阅读!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/39703.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Vue2计算属性如何传参

Vue2官网并没解释计算属性应该怎么传值&#xff0c;但是呢&#xff0c;通过闭包的方式(使用箭头表达式)实际上是可以给计算属性传参的&#xff08;当然&#xff0c;多个参数也是可行的&#xff09;。 以下是本人项目开发使用自己基于ElementUI封装的集信息采集与文件上传功能的…

微信小程序基于Promise封装发起网络请求

1.创建一个request.js // 相当于域名 const baseURL ***************; // 暴露一个request函数 export function request(parms) {// 路径拼接const url baseURL parms.url;// 请求体&#xff0c;默认为{}const data parms.data || {};// 请求方式&#xff0c;默认为GETco…

攻防世界-web-easytornado

题目描述&#xff1a;Tornado 框架。打开链接是一个简单的界面 1. 思路分析 看到有个/flag.txt&#xff0c;我们点击进去看下 发现传入了两个参数&#xff0c;一个是filename&#xff0c;还有一个是filehash 看到里面的内容&#xff0c;提示我们真正的flag在 /flllllllllllla…

curl操作

下载路径&#xff1a;https://curl.se/windows/ 参考&#xff1a;https://blog.csdn.net/weixin_45191386/article/details/130652821 操作&#xff1a; curl http://localhost:8085/api/v1/aaa/bbbb/?ccc 652781344055627776

docker在arm64架构ubuntu系统的安装

卸载可能存在的旧版本 sudo apt remove docker docker-engine docker-ce docker-io安装依赖使apt可通过HTTPS下载包 sudo apt update && apt install -y apt-tranport-https ca-certificates curl software-properties-commonapt-transport-https用于支持通过HTTPS协…

能源监测系统:实时监控+数据可视化

能源监测系统是应用物联网技术&#xff0c;对水、电、气、热等能源进行实时监测的系统&#xff0c;能够对各种设备数据进行智能化标准化的管理&#xff0c;从而建立起统一的管理优化平台&#xff0c;是积极响应国家节能降耗政策的典型模范&#xff0c;也是企业建设节能型工厂的…

自动化测试工具比传统测试工具的优势体现在哪里?

随着软件行业的快速发展和扩张&#xff0c;自动化测试工具在提高测试效率和质量方面起到了不可或缺的作用&#xff0c;那你知道自动化测试工具比传统测试工具的优势体现在哪里吗&#xff1f; 首先&#xff0c;自动化测试工具能够大大缩短测试周期。相比于传统手动测试&#xff…

Offset Explorer2 监视kafka的利器

kafka作为一个生产者和消费者集为一体的框架&#xff0c;消费者必须一直保持打开的状态&#xff0c;并且每隔一段时间接收一次数据&#xff0c;才能够保持生产者放入的数据及时被处理掉&#xff0c;而生产者则可以每隔一段时间发送一波数据&#xff0c;这样消费者就能够接收到了…

红队打靶:KIOPTRIX1.2打靶思路详解(vulnhub)

目录 写在开头 第一步&#xff1a;主机发现和端口扫描 第二步&#xff1a;Web渗透与CMS漏洞利用 第三步&#xff1a;敏感信息搜索 第四步&#xff1a;SSH登录与提权 总结与思考 写在开头 本篇博客根据大佬红队笔记的视频进行打靶&#xff0c;详述了打靶的每一步思路&a…

pytest实现用例间参数传递的方式

pytest实现用例间参数传递的方式 一、通过conftest创建全局变量二、使用tmpdir_factory方法 我们在做接口自动化测试的时候&#xff0c;会经常遇到这种场景&#xff1a;接口A的返回结果中的某个字段&#xff0c;是接口B的某个字段的入参。如果是使用postman&#xff0c;那我们可…

Office如何通过VSTO进行PPT插件开发?

文章目录 0.引言1.工具准备2.PPT外接程序创建和生成3.外接程序生成并使用 0.引言 VSTO&#xff08;Visual Studio Tools for Office &#xff09;是VBA的替代&#xff0c;是一套用于创建自定义Office应用程序的Visual Studio工具包。VSTO可以用Visual Basic 或者Visual C#扩展O…

php裁剪图片,并给图片加上水印

本次以裁剪四个图片为例&#xff0c;图片如下 代码如下 public function cutImg($imgUrl){try{// 读取原始图片$src_img imagecreatefromjpeg($imgUrl);// 获取原始图片的宽度和高度$src_width imagesx($src_img);$src_height imagesy($src_img);// 计算每个部分的宽度和高…

ROS:pluginlib

目录 一、前言二、概念三、作用四实际用例4.1需求4.2流程4.3准备4.4创建基类4.5创建插件4.6注册插件4.7构建插件库4.8使插件可用于ROS工具链4.8.1配置xml4.8.2导出插件 4.9使用插件4.10执行 一、前言 pluginlib直译是插件库&#xff0c;所谓插件字面意思就是可插拔的组件&…

学习react,复制一个civitai-更新2

更新内容 耗时一个礼拜左右&#xff0c;增加了个新界面&#xff1a;模型图片详情界面。 看看效果图吧&#xff1a; 功能介绍 操作&#xff1a;在模型详情界面点击一个图片&#xff0c;就能到图片详情界面 1.点击哪个图片&#xff0c;就会展示哪个&#xff0c;同时还会更新图…

vue-element-admin解决跨域问题

更改vue.config.js publicPath: process.env.NODE_ENV production ? /tyzfadmin : /,//开发和生产环境不一样&#xff0c;做个判断 outputDir: dist, assetsDir: static, lintOnSave: false, runtimeCompiler: true, productionSourceMap: false, devServer: {port: port,op…

暴雪娱乐遭DDoS攻击,《暗黑破坏神》等多款游戏受影响

6月25日上午11点&#xff0c;有游戏玩家反应Blizzard Battle.net无法登入、连线缓慢及网站问题&#xff0c;暴雪也证实其电玩平台遭到DDoS攻击。 暴雪娱乐的 Battle.net在线服务遭到分布式拒绝服务&#xff08;DDoS&#xff09;攻击&#xff0c;导致玩家无法正常登录游戏或游戏…

虚幻Voxel插件

虚幻Voxel插件 Voxel Plugin Voxel Plugin brings smoothed voxel terrain to Unreal Engine 4. Generate, destroy and terraform the world! 体素插件可以在虚幻引擎中生成平滑的体素地形。创造、破环和改造世界。 Terrain generation and terraforming both in game and i…

MFC第十八天 非模式对话框、对话框颜色管理、记事本项目(查找替换、文字和背景色、Goto(转到)功能的开发)

文章目录 非模式对话框非模式对话框的特点非模式对话框与QQ聊天窗口开发非模态对话框&#xff08;Modeless Dialog&#xff09;和模态对话框&#xff08;Modal Dialog&#xff09;区别 记事本开发CFindReplaceDialog类的成员查找替换(算法分析)使用RichEdit控件 开发Goto(转到)…

Minecraft 1.20.x Forge模组开发 01.Idea开发环境配置

我们本次来进行Minecraft 1.20.x 模组开发环境配置教程的介绍。 效果演示 效果演示 效果演示 1.首先我们需要下载Java17和1.20模组开发包: Java17下载官网

ylb-项目简介

1、各模块服务功能 注&#xff1a;其部分实体类、接口、mapper文件由MyBatis逆向工程生成。 2、Maven管理&#xff08;多模块&#xff0c;继承和聚合&#xff09; 2.1 parent模块 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"…