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

news2024/11/28 0:37:47

文章目录

    • ⭐前言
    • ⭐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

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

4.3.tensorRT基础(1)-实现模型的推理过程

目录 前言1. inference案例总结 前言 杜老师推出的 tensorRT从零起步高性能部署 课程&#xff0c;之前有看过一遍&#xff0c;但是没有做笔记&#xff0c;很多东西也忘了。这次重新撸一遍&#xff0c;顺便记记笔记。 本次课程学习 tensorRT 基础-实现模型的推理过程 课程大纲可…

深度学习——LSTM解决分类问题

RNN基本介绍 概述 循环神经网络&#xff08;Recurrent Neural Network&#xff0c;RNN&#xff09;是一种深度学习模型&#xff0c;主要用于处理序列数据&#xff0c;如文本、语音、时间序列等具有时序关系的数据。 核心思想 RNN的关键思想是引入了循环结构&#xff0c;允许…

JavaBeans

Code eamples ① Product.java (JavaBean Class) ② Bean.java (Servlet) ③ complie javac -encoding utf-8 -d ..\classes -sourcepath . chapter15\Bean.java ④ Tomcat ⑤ http://localhost:8080/book/chapter15/bean

flink水位线传播及任务事件时间

背景 本文来讲解一下flink的水位线传播及对其对任务事件时间的影响 水位线 首先flink是通过从源头生成水位线记录的方式来实现水位线传播的&#xff0c;也就是说水位线是嵌入在正常的记录流中的特殊记录&#xff0c;携带者水位线的时间戳&#xff0c;以下我们就通过图片的方…

Docker常用命令(三)

1、镜像命令 1、列出本地主机上的镜像 docker images [options]optiins说明&#xff1a; -a&#xff1a;列出本地所有的镜像&#xff08;包含历史映像层&#xff09; -q&#xff1a;只显示镜像ID2、搜索某个镜像信息 docker search [options] 镜像名字3、下载镜像 docker …

Kafka第二课-代码实战、参数配置详解、设计原理详解

一、代码实战 一、普通java程序实战 引入依赖 <dependencies><dependency><groupId>org.apache.kafka</groupId><artifactId>kafka-clients</artifactId><version>2.4.1</version></dependency><dependency>&l…

windows环境hadoop报错‘D:\Program‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件。

Hadoop版本为2.7.3&#xff0c;在环境配置好后&#xff0c;检查hadoop安装版本&#xff0c;报如标题所示错误&#xff0c;尝试网上主流的几种方法均无效。 错误&#xff1a;windows环境hadoop报错’D:\Program’ 不是内部或外部命令,也不是可运行的程序 或批处理文件。 错误方…

Jackson使用

导入依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.0.0…

静态输出调节

1.理论部分 15. SISO反馈控制器设计 (6)&#xff1a;输出调节-静态反馈 Output Regulation - 知乎 (zhihu.com) 上述博客已经写的很好了&#xff0c;过多描述 2.仿真实验 3.参考理论 首先通过18式求解出X和U&#xff0c;然后设计一个让原系统初始稳定的控制律Kx&#xff0c;…

第二周习题

2.创建类MyDate,year属性和month属性,编写一个方法totalDays,该方法通过年份和月份判断该月一共有多少天,在主函数中接受用户输入年和月&#xff0c;调用该方法测试它. 这里考虑平年和闰年 “平年2月有28天。闰年的2月有29天 那么就有区别了 只要判断这一点就行了&#xff01;&…

框架开发使用注解处理器APT优雅提效

目录 概述1.什么是注解处理器APT2.应用场景3.如何使用3.1 创建注解API模块3.2 创建注解处理器模块3.3 使用注解 概述 在现在的很多开源框架中&#xff0c;我们经常能在源码中看到注解处理器的影子&#xff0c;比如我们熟悉的阿里的ARouter,Android开发中的替代findViewById神器…

【git】git以及可视化界面下载安装

git 以及可视化界面下载安装 git下载安装测试功能 sourceTree下载安装 git 下载安装 下载地址 git官网上有多个版本&#xff0c;点击“Click here to download” &#xff0c;下载下来之后&#xff0c;一直下一步安装即可 测试功能 在任意文件夹中右击&#xff0c;看到图中…

Linux三剑客

前言 关于bash&#xff1a; bash&#xff1a;命令处理器&#xff0c;运行在文本窗口&#xff0c;能够执行用户输入的命令。 脚本&#xff1a;从linux文件中读取命令&#xff0c;被称为脚本。 1 命令&#xff1a;alias&#xff1a;起别名 2 快捷键操作&#xff1a; ctrla&#…

浅谈如何提高自动化测试的稳定性和可维护性

目录 前言&#xff1a; 装饰器与出错重试机制 什么是装饰器&#xff1f; 编写一个出错重试装饰器 pytest 里的出错重试机制实现 Allure 里的测试用例分层 为什么要采用分层机制&#xff1f; allure 的装饰器step 前言&#xff1a; 自动化测试在软件开发中扮演着重要的…

Fortran lapack求数组的特征值,特征向量

call zgeev(V, V, n, arr, lda, w, vl, ldvl, vr, ldvr, work, lwork, rwork, info) 这个函数是求矩阵的特征值&#xff0c;且结果是双精度复数的情况&#xff0c;具体可以查MKL的官方文档。 如果是单精度复数就要用cgeev&#xff0c;其中的参数也是将双精度改为单精度即可。…

Hive,FineBI-30W聊天数据分析及可视化-B站黑马学习记录

2023B站黑马Hadoop、Hive、云平台实战项目 目录 1. 清洗数据 2. 计算各指标&#xff0c;并创建表存储结果 3.FineBI连接Hive数据库&#xff0c;将指标结果可视化 1. 清洗数据 1&#xff09;部分数据缺失地理位置信息&#xff08;sender_gps&#xff09;&#xff0c;需要剔…

Linux下的调试器——gdb使用指南

文章目录 一.序二.安装gdb调试器三.进入调试四.调试相关指令 前言&#xff1b; 在VS环境下&#xff0c;我们不仅可以写代码、编译、运行可执行程序&#xff0c;还可以对生成的可执行程序进行调试。本章我们就来学习如何在Linux环境下进行调试。 一.序 要进行调试&#xff0c;首…

EPICS一个示例数据库实例详解

以下是一个示例数据库图表&#xff1a; 以上记录的数据库文件如下&#xff1a; record(ao, "$(P):SET") {field(FLNK, "$(P):ACTIVATE")field(VAL, "2")field(OUT, "$(P):RUN")field(DRVH, "40")field(DRVL, "5"…

摩尔投票算法(Moore‘s Voting Algorithm)及例题

摩尔投票算法&#xff08;Moores Voting Algorithm&#xff09;及例题 摩尔投票算法简介摩尔投票算法算法思想摩尔投票算法经典题目169. 多数元素229. 多数元素 II6927. 合法分割的最小下标 上午打力扣第 354 场周赛最后十五分钟用摩尔投票算法顺利 AC 第三题&#xff0c;以前没…

ViewRootImpl简析

ViewRootImpl简析 如何实现视图和wms沟通桥梁的作用Session的创建获取画布如何实现事件分发的桥梁作用 The top of a view hierarchy, implementing the needed protocol between View and the WindowManager. This is for the most part an internal implementation detail of…