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



    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
    };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103

    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");
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118

    回调html

    DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>qqLoginCallbacktitle>
    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>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    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)
                }
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93

    效果:

    quick_qq_login

    ⭐结束

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

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

  • 相关阅读:
    「太阁干货」华为模拟器eNSP安装教程
    vue的两种服务器端渲染方案
    【JavaEE网络】TCP套接字编程详解:从概念到实现
    【数据结构与算法分析】0基础带你学数据结构与算法分析03--栈 (Stack)
    【超详细,面向初学者】如何用Idea快速创建一个MyBatis项目?导入坐标-创建数据库-成功运行示例
    铁蛋白颗粒Tf包载多肽/凝集素/细胞色素C/超氧化物歧化酶/多柔比星(定制服务)
    dubbo面试题
    论文笔记:A survey of deep nonnegative matrix factorization
    c# 解决CS8602告警 解引用可能出现空引用
    Elasticsearch:wildcard - 通配符搜索
  • 原文地址:https://blog.csdn.net/qq_38870145/article/details/131750832