第三方登入例子-GitHub授权登入(node-koa)

前言

第三方登入太常见了,微信,微博,QQ...总有一个你用过。当然看这篇文章的你,应该还用过github登入。这篇分享是在上一篇基于node的登入例子(node-koa-mongoose)的基础增加了github账号第三方授权登入功能,如果有些代码,这篇中美介绍,你可以先去看下上一篇的分享。

本项目源码地址https://github.com/linwalker/node-login

第三方登入

第三方登入主要基于OAuth 2.0。OAuth协议为用户资源的授权提供了一个安全的、开放而又简易的标准。与以往的授权方式不同之处是OAUTH的授权不会使第三方触及到用户的帐号信息(如用户名与密码),即第三方无需使用用户的用户名与密码就可以申请获得该用户资源的授权,因此OAUTH是安全的 ---- 百度百科

更详细的介绍可以看这篇文章理解OAuth 2.0

github 授权登入

原理过程

先来大致了解下第三方通过GitHub账号授权登入的过程,具体实现结合后面代码讲解

  • 1.获取code

    第三方客户端向https://github.com/login/oauth/authorize发送get请求,带上?client_id=XXXXXX参数,这时会跳转到GitHub登入页面,授权后GitHub会向客户端返回https://redirect_url?code=XXXXXX。其中client_idredirect_url是第三方事先在GitHub平台上配置好的。

  • 2.通过code获取access_token

    客户端处理https://redirect_url?code=XXXXXX请求,获取code值,向https://github.com/login/oauth/access_token发起post请求,请求参数为client_di,client_secretcode

  • 3.通过access_token获取用户GitHub账号信息

第二步的请求会返回这样access_token=d0686dc49a22d64e77402db072b719f510f22421&scope=user&token_type=bearer的内容,只需要向https://api.github.com/user?access_token=xxx发送GET请求,即可获取到登录用户的基本信息,

具体实现

GitHub注册应用

首先你要有一个GitHub账号,然后进入settings -> OAuth application -> Register a new application。进来后你会看到下面这个页面:

应用注册(github-login).png

依次填好应用名称,应用地址和授权回掉地址后点击Register application按钮,会生成一个client Idclient Secret,用于后面向GitHub发送请求传参。

生成ID和Secret(github-login).png

Github授权请求(获取code)

在页面中添加GitHub登入跳转按钮,并在路由中对跳转请求进行转发处理:

//在node-login/components/LoginTab.js

<a href="/github/login">
     <Icon type="github" style={{fontSize: 20, color: '#000'}}/>
</a>
点击登入(github-login).png

添加跳转按钮后,增加相应路由处理,路由入口中添加/github路径处理

//在node-login/routes/index.js

const github = require('./github');
router.use('/github', github.routes(), github.allowedMethods());

最后是具体的路由处理

//在node-login/routes/github.js
const config = require('../config');
const router = require('koa-router')();
const fetch = require('node-fetch');
const routers = router
    .get('/login', async (ctx) => {
        var dataStr = (new Date()).valueOf();
        //重定向到认证接口,并配置参数
        var path = "https://github.com/login/oauth/authorize";
        path += '?client_id=' + config.client_id;
        path += '&scope=' + config.scope;
        path += '&state=' + dataStr;
        //转发到授权服务器
        ctx.redirect(path);
    })
module.exports = routers;

在config中事先添加配置请求所需参数client_idclient_secretscope

module.exports = {
    'database': 'mongodb://localhost:27017/node-login',
    'client_id': '83b21756e93d6ce27075',
    'client_secret': 'd87c4163ece5695a9ded1e8bf2701c5ee2651f28',
    'scope': ['user'],
};

其中scope参数可选。就是你期待你的应用需要调用Github哪些信息,可以填写多个,以逗号分割,比如:scope=user,public_repo。state参数非必需,用于防治跨域伪造请求攻击。

现在可以运行一下项目,点击小黑猫,跳转到授权登入页面(没登入过,要输入账号密码),授权成功返回回掉地址。

授权(github-login).png

回掉地址中code就是返回的授权码,通过授权码再去获取令牌access_token

授权回掉(github-login).png

授权回掉处理(获取access_token)

在第一授权请求https://github.com/login/oauth/authorize成功后GitHub会给应用返回一个回掉http://localhost:3003/github/oauth/callback?code=14de2c737aa02037132d&state=1496989988474。这个回掉地址就是之前在GitHub注册应用时填入的回掉地址,另外还带了需要的code参数,state就是上一步请求中带的state参数,原样返回。

现在我们要对这个回掉请求进行处理:

//node-login/routes/github.js
const config = require('../config');
const router = require('koa-router')();
const fetch = require('node-fetch');
const routers = router
    .get('/login', async (ctx) => {
        ...
    })
    .get('/oauth/callback', async (ctx) => {
        const code = ctx.query.code;
        let path = 'https://github.com/login/oauth/access_token';
        const params = {
            client_id: config.client_id,
            client_secret: config.client_secret,
            code: code
        }
        console.log(code);
        await fetch(path, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(params)
        })
        .then(res => {
            return res.text();
        })
        .then(body => {
            ctx.body = body;
        })
       .catch(e => {
            console.log(e);
        })
    })
module.exports = routers;

GitHub返回回掉地址时,先拿到请求中的code参数,然后向https://github.com/login/oauth/access_token发送post请求并带上client_id,client_secret,code参数,请求成功后会返回带有access_token的信息。

access_token(github-login).png

获取GitHub账号信息

最后带上获取的access_token请求https://api.github.com/user?access_token=xxx,返回的就是之前scope中对应的账号信息。

.get('/oauth/callback', async (ctx) => {
        const code = ctx.query.code;
        let path = 'https://github.com/login/oauth/access_token';
        const params = {
            client_id: config.client_id,
            client_secret: config.client_secret,
            code: code
        }
        console.log(code);
        await fetch(path, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(params)
        })
        .then(res => {
            return res.text();
        })
        .then(body => {
            const args = body.split('&');
            let arg = args[0].split('=');
            const access_token = arg[1];
            console.log(body);
            console.log(access_token);
            return access_token;
        })
        .then(async(token) => {
            const url = ' https://api.github.com/user?access_token=' + token;
            console.log(url);
            await fetch(url)
                .then(res => {
                    return res.json();
                })
                .then(res => {
                    console.log(res);
                    ctx.body = res;
                })
        })
        .catch(e => {
            console.log(e);
        })
    })

返回的用户信息如下:

user_info(github-login).png

总结

用一张图来总结

原理过程(github-login).png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,580评论 18 139
  • OAuth2.0协议 定义 OAuth: OAuth(开放授权)是一个开放标准,允许用户授权第三方移动应用访问他们...
    HoooChan阅读 5,366评论 1 3
  • afinalAfinal是一个android的ioc,orm框架 https://github.com/yangf...
    passiontim阅读 15,393评论 2 45
  • 如果你不幸点开了这个页面,请义无反顾的关掉,阅读以下文字会给你的身心造成巨大的折磨,它既不美观,也无趣。 最近越来...
    特瓅忒呖呖阅读 289评论 0 0
  • 她大三了,不喜欢自己的专业。我提醒她,要考研的话应该准备了。她说,她的人脉不行。她想考别的专业,但跨校、跨系没有人...
    暗香盈梦阅读 250评论 0 0