使用OAuth2.0协议的github、QQ、weibo第三方登录接入总结
第三方接入总结
本文主要讲解OAuth2.0协议和github、微博、QQ三个平台提供的接入流程,介绍nodejs下十分好用的认证授权插件passport.js。本文代码基于nodejs-express。
OAuth2.0介绍
在说OAuth协议之前,想说一下OpenID。在2005年的夏天,一个开源社区为了解决一个其它现有web身份认证技术不容易解决的问题时,制定了OpenID,OpenID是一个认证(Authentication)协议,这个协议让第三方应用程序在不获取你密码的情况下认证你的身份,OpenID和OAuth是两个经常放在一起比较的web身份认证技术,但OAuth比起OpenID,更像是一个授权(Authorization)协议,是让第三方应用程序在不获取你密码的情况下获取你的授权去对授权提供商或者说是资源提供商请求你授权的资源,拿到OpenID就像给别人指,这栋房子是我的,我可以拿点东西给你看看,而拿到OAuth授权就像你给别人说,这栋房子是我的,这个钥匙给你,但只能开大门不能进卧室,哪些可以动哪些可以开都是你说了算,并且你可以随时方便的收回这把钥匙。
OAuth2.0是2006年提出来的新一代OAuth版本,比起OAuth1.x,它简化了认证交互过程,增加了认证机制,使用了SSL,去掉了一个叫做客户端token secret的东西,这也导致了OAuth升级需要改动代码,并且没有了1.0版本的安全bug(1.0a修复),这个安全bug主要是回调地址设定方式导致的。
OAuth2.0协议主要有四个角色,资源所有者即用户,资源服务器,授权服务器和用户代理即客户端,这四个角色主要是完成了这样一个流程,客户端与服务器提供商之前,有一个通过OAuth协议完成的授权服务器,客户端有从服务端获取的唯一ID,客户端不能直接登录服务器提供商,需要先通过用户在授权服务器取得授权码,并且拿着获得用户授权的授权码在授权层换取accessToken,通过这个token向资源服务器请求用户授权信息。
github OAuth2.0登录接入
OAuth2.0客户端一共有4种授权模式,授权码模式(authorization code)、简化模式(implicit)、密码模式(resource owner password credentials)和客户端模式(client credentials),在github提供的OAuth.v3接口中,使用的是授权码模式,在这种模式中,客户端需要引导用户重定向请求到Github的OAuth认证接口,带上在授权服务器申请的客户端 client_id,配置的回调地址 redirect_uri ,申请授权的scope,你也可以带上状态值state,服务器会在回调中原封不动地返回你这个值,这一步将会换取前面我们说到的授权码code,具体流程和代码实现如下:
1.首先我们需要在github上新建一个应用(记得登录),获取客户端的Client ID和Client Secret并配置好回调地址。

2.重定向到OAuth认证接口 GET https://github.com/login/OAuth/authorize
<a href= '/mygithub'></a>
3.发起重定向请求到授权服务器换取code
var express = require('express');
app.get('/mygithub', function(req, res) {
var dataStr = (new Date()).valueOf();
//重定向到认证接口,并配置参数
//注意这里使用的是node的https模块发起的请求
var path = "https://github.com/login/OAuth/authorize";
path += '?client_id=' + OAuthConfig.GITHUB_CLIENT_ID;
path += '&scope='+OAuthConfig.GITHUB_CLIENT_SCOPE;
path += '&state='+ dataStr;
//转发到授权服务器
res.redirect(path);
});
通过第一步的请求,如果用户正确授权,换取的code和上一步传输的state会被服务器作为回调参数,放在你在这里配置的回调地址上,但是如果授权服务器返回的state和第一步传入的不一致,根据OAuth2.0协议,开发者应该中止这个请求。拿到了code后,开发者应该在回调地址处重定向请求到授权服务器利用client_id、client_secret和code换取access_token,这个access_token就是你开启开门的钥匙,拿到钥匙后你可以本地存储钥匙或者根据scope马上向资源服务器请求数据,具体流程和代码实现如下:
app.get("/OAuth/github_v2/callback", function(req, res){
var code = req.query.code;
var state = req.query.state;
var headers = req.headers;
var path = "/login/OAuth/access_token";
headers.host = 'github.com';
path += '?client_id=' + OAuthConfig.GITHUB_CLIENT_ID;
path += '&client_secret='+OAuthConfig.GITHUB_CLIENT_SECRET;
path += '&code='+ code;
console.log(path);
var opts = {
hostname:'github.com',
port:'443',
path:path,
headers:headers,
method:'POST'
};
//注意这里使用的是node的https模块发起的请求
var req = https.request(opts, function(res){
res.setEncoding('utf8');
console.log(opts);
//解析返回数据
res.on('data', function(data){
var args = data.split('&');
var tokenInfo = args[0].split("=");
var token = tokenInfo[1];
console.log(data);
//利用access_token向资源服务器请求用户授权数据
var url = "https://api.github.com/user?access_token="+token&scope="user";
https.get(url, function(res){
res.on('data', function(userInfo){
console.log(userInfo);
});
});
})
});
});
至此,你就可以拿着token获取用户授权的信息了,但是token也会过期,需要重新请求。
scope是OAuth协议提供权限范围选项,避免让第三方应用有了一个钥匙就打开了用户所有的门,在github中,你可以打开的门如下:

国内第三方应用商SDK使用
除了用原生的OAuth协议去获取用户授权,我们也可以使用一些第三方应用提供商的SDK来实现快速地接入,特别是国内的许多平台都提供了集成OAuth协议的SDK,使用这种SDK可以帮你快速对现有网站进行集成,但是缺点对开发测试很不友好,比如需要你是上线的网站并且在验证的时候它会默认去访问服务器80端口,如果你的那台测试服务器刚好http端口在做其他事情,这就很尴尬了。
下面我就微博和腾讯QQ的接入来简单介绍一下。
微博SDK
使用微博SDK之前,你需要先在微博开放平台验证网站所有权,微博有一点特别不好的就是在这里接入的地址不能指定端口,再在这里下载相应的SDK。
准备工作做好之后,开发起来就相当便利了。
- 首先在网站的首页添加一个meta标签。
meta(property="wb:webmaster" content="YOUR_KEY")
添加一个meta标签以便微博服务器识别你的身份,微博会对你在验证网站所有权配置的地址进行http访问,来查询是否有正确的meta,不过微博的实现好像不是很好,经常会告诉你验证失败,当然QQ也一样。
- 引入js SDK
在appkey填入你申请的appkey,并且开启debug模式方便调试
script(src="http://tjs.sjs.sinajs.cn/open/api/js/wb.js?appkey=YOUR_APPKEY&debug=true" type="text/javascript" charset="utf-8")
- 简单地调用
完成了上面的资源引用,对于我们的授权接入,只需简单放置如下代码即可
<div id="wb_connect_btn"></div>
WB2.anyWhere(function (W) {
W.widget.connectButton({
id: "wb_connect_btn",//按钮id
type: '3,2',//按钮样式,[这里](http://open.weibo.com/widget/loginbutton.php)可以设置
callback: {
login: function (o) { //登录后的回调函数
alert("login: " + o.screen_name)
},
logout: function () { //退出后的回调函数
alert('logout');
}
}
});
});
- 相关文档
腾讯QQ SDK
腾讯SDK的使用方式和微博SDK差别不大,最好的一点就是腾讯的SDK如果回调地址是当前页面,可以不用配置回调地址就可以快速接入。当然你也需要在这里注册申请appkey
- 首先在网站的首页添加一个meta标签。
meta(property="qc:admins" content="YOUR_KEY")
- 引入js SDK
script(type="text/javascript" src="http://qzonestyle.gtimg.cn/qzone/openapi/qc_loader.js" data-appid="YOUR_APPKEY" charset="utf-8")
腾讯的SDK会默认有很多日志在控制台输出。你可以看到你有什么错误。
- 简单地调用
<span id="qqLoginBtn"></span>
QC.Login({
btnId: "qqLoginBtn", //插入按钮的节点id
size: "C_S" //按钮样式
}, function(reqData, opts) {
var dom = document.getElementById('user_login'),
_logoutTemplate = [
//头像
'<span><img src="{figureurl}" class="{size_key}"/></span>',
//昵称
'<span>{nickname}</span>',
//退出
'<span><a style="color:white" href="javascript:QC.Login.signOut();">退出</a></span>'
].join("");
dom && (dom.innerHTML = QC.String.format(_logoutTemplate, {
nickname: QC.String.escHTML(reqData.nickname), //做xss过滤
figureurl: reqData.figureurl
}));
$('#user_login').removeClass('hide');
}, function(opts) { //注销成功
console('QQ登录 注销成功');
});
- 相关文档
passport.js插件使用
如果对于每个接入都要去使用这个第三方应用提供商的SDK,那么对于一个开发者,花在学习调试开发上面的时间会成倍增加,既然现在主流的第三方登录都适用的OAuth协议,那么我们可不可以根据这个流程封装一套通用的SDK呢?答案当然是可以的,并且前人已经为我们造好了轮子。
在Node平台,最出名的认证插件当然非passport.js莫属了,在它的官网上你可以很容易的搜索到各种第三方应用登录策略,只需简单的npm install,你就可以进行OAuth认证授权了。点击官网上面的Strategies字样搜索你想要的登录策略。
passport目前拥有300+的第三方应用接入策略,支持持久化session,拥有简单易用的回调处理函数,同时支持OpenID 和 OAuth。
安装
github v3 接口实现、qq、weibo的passport.js插件
npm install passport-github2
npm install passport-qq
npm install passport-weibo
相关中间件、路由
我们使用express来做为我们的web框架,使用passport.js做我们的认证插件,在这个例子中我们仅仅介绍passport-github2的使用,QQ和weibo插件的使用和passport-github2一模一样。需要引入如下几个库
var express = require('express');
var passport = require('passport');
var util = require('util');
var session = require('express-session');
var bodyParser = require('body-parser');
var methodOverride = require('method-override');
var GitHubStrategy = require('passport-github2').Strategy;
var partials = require('express-partials');
第一步,序列化与反序列化session值,以支持持久化登录,这步以后你可以方便的在passport的session模块中根据你序列化的唯一值(一般为ID),来处理用户的登录状态和登录信息等
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(obj, done) {
done(null, obj);
});
第二步,使用在passport.js中使用GitHub的认证策略GitHubStrategy,形如这样的策略函数是passport中的一个‘认证’函数,它的回调接受accessToken, refreshToken和第三方返回的用户信息,这里是GitHub profile。
passport.use(new GitHubStrategy({
clientID: YOUR_GITHUB_CLIENT_ID,
clientSecret: YOUR_GITHUB_CLIENT_SECRET,
callbackURL: "http://127.0.0.1/auth/github/callback",//第三方应用申请页面填写的回调地址
passReqToCallback: true//会传输req对象
},
function(req,accessToken, refreshToken, profile, done) {
console.log(profile);
process.nextTick(function() {
//在这里你可以对profile进行处理,比如进行存储或者方便
if(req.user){
//...绑定
app.db.models.User.findOne({...},function(){
....
})
}
else{
//...新建一个用户
var user = new app.db.models.User();
user.github = profile;
user.save();
}
//...或者存储accessToken
return done(null, profile);
});
}
));
第三步,对express进行配置,和以往的express配置没有太多不同,只需要调用中间价passport的initialize和session去初始化passport和它的session模块。
var app = express();
// configure Express
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
app.use(partials());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(methodOverride());
app.use(session({ secret: 'keyboard cat', resave: false, saveUninitialized: false }));
app.use(passport.initialize());
app.use(passport.session());
app.use(express.static(__dirname + '/public'));
第四步,配置路由
需要引导用户点击/auth/github,使用passport.authenticate()做为路由中间件去授权认证请求,passport.js插件会重定向用户到github的授权页,用户点击授权后github会把用户重定向到你之前申请应用时填写的回调地址,我们在回调地址/auth/github/callback中接受用户信息,并且利用passport.authenticate()做为路由中间件去检查授权是否成功以及引导相应路由。
app.get('/', function(req, res) {
res.render('index', { user: req.user });
});
app.get('/account', ensureAuthenticated, function(req, res) {
res.render('account', { user: req.user });
});
app.get('/login', function(req, res) {
res.render('login', { user: req.user });
});
// GET /auth/github
app.get('/auth/github',
passport.authenticate('github', { scope:YOUR_GITHUB_CLIENT_SCOPE }),
function(req, res) {
// The request will be redirected to GitHub for authentication, so this
// function will not be called.
});
// GET /auth/github/callback
app.get('/auth/github/callback',
passport.authenticate('github', { failureRedirect: '/login' }),
function(req, res) {
//这里可以重定向到用户界面等页面,现在已经拿到用户信息和存储了session。
res.redirect('/');
});
返回字段(2016年8月23日获取)
_json值是格式化的raw值,故所有返回字段皆省略raw字段
注意QQ的_json字段中并没有id值,与github和weibo不同
{ provider: 'qq',
id: '',
nickname: '',
_raw: '...',
_json:
{ ret: 0,
msg: '',
is_lost: 0,
nickname: '',
gender: '男',
province: '四川',
city: '成都',
year: '1994',
figureurl: '',
figureurl_1: '',
figureurl_2: '',
figureurl_qq_1: '',
figureurl_qq_2: '',
is_yellow_vip: '0',
vip: '0',
yellow_vip_level: '0',
level: '0',
is_yellow_year_vip: '0' }
}
{ provider: 'weibo',
id: '',
displayName: '',
_raw:
{ ...},
_json:
{ id: ,
idstr: '',
class: 1,
screen_name: '',
name: '',
province: '44',
city: '3',
location: ' ',
description: '',
url: '',
profile_image_url: '',
cover_image: '',
profile_url: '',
domain: '',
weihao: '',
gender: 'm',
followers_count: ,
friends_count: ,
pagefriends_count: ,
statuses_count: ,
favourites_count: ,
created_at: '',
following: false,
allow_all_act_msg: false,
geo_enabled: true,
verified: true,
verified_type: 2,
remark: '',
status:
{ created_at: 'Tue Aug 23 15:22:14 +0800 2016',
id: ,
mid: '',
idstr: '',
text: '',
textLength: 60,
source_allowclick: 0,
source_type: 1,
source: '',
favorited: false,
truncated: false,
in_reply_to_status_id: '',
in_reply_to_user_id: '',
in_reply_to_screen_name: '',
pic_urls: [Object],
thumbnail_pic: '',
bmiddle_pic: '',
original_pic: '',
geo: null,
reposts_count: 0,
comments_count: 0,
attitudes_count: 0,
isLongText: false,
mlevel: 0,
visible: [Object],
biz_feature: 0,
page_type: 32,
hasActionTypeCard: 0,
darwin_tags: [],
hot_weibo_tags: [],
text_tag_tips: [],
userType: 0,
positive_recom_flag: 0,
gif_ids: '',
is_show_bulletin: 2 },
ptype: 0,
allow_all_comment: true,
avatar_large: '',
avatar_hd: '',
verified_reason: '',
verified_trade: '',
verified_reason_url: '',
verified_source: '',
verified_source_url: '',
verified_state: 0,
verified_level: 3,
verified_type_ext: 0,
verified_reason_modified: '',
verified_contact_name: '',
verified_contact_email: '',
verified_contact_mobile: '',
follow_me: false,
online_status: 0,
bi_followers_count: 94,
lang: 'zh-cn',
star: 0,
mbtype: 0,
mbrank: 0,
block_word: 0,
block_app: 0,
credit_score: 80,
user_ability: 4,
urank: 19 } }
- github
{ id: '',
displayName: null,
username: '',
profileUrl: '',
emails: [ { value: '' } ],
provider: 'github',
_raw: '{...}',
_json:
{ login: '',
id: ,
avatar_url: '',
gravatar_id: '',
url: '',
html_url: '',
followers_url: '',
following_url: '',
gists_url: '',
starred_url: '',
subscriptions_url: '',
organizations_url: '',
repos_url: '',
events_url: '',
received_events_url: '',
type: 'User',
site_admin: false,
name: null,
company: null,
blog: null,
location: null,
email: '',
hireable: null,
bio: null,
public_repos: 0,
public_gists: 0,
followers: 0,
following: 0,
created_at: '2016-07-15T06:17:35Z',
updated_at: '2016-08-18T08:06:49Z',
private_gists: 0,
total_private_repos: 0,
owned_private_repos: 0,
disk_usage: 0,
collaborators: 0,
plan:
{ name: 'free',
space: ,
collaborators: 0,
private_repos: 0 } } }
QQ和微博申请和审核
最后简单介绍一下QQ和weibo的应用申请和审核。
微博weibo
- 第一步,新建应用
- 第二步,填写应用信息,尽量详细,特别是应用图标,以方便通过审核。

- 第三步,填写回调地址,可以配置非80端口

- 第四步,点击审核,进入审核状态,等待weibo通过。

腾讯QQ
- 第一步,新建应用,点击创建应用,选择网站
- 第二步,填写应用信息,注意回调地址不能有端口号,默认访问80。

- 第三步,在信息编辑中,填写配置协作者账号,方便开发测试。

- 第四步,点击审核,进入审核状态,等待QQ通过。

相关文档
使用OAuth2.0协议的github、QQ、weibo第三方登录接入总结的更多相关文章
- Oauth2.0 协议简介及 php实例代码
转自:http://www.dahouduan.com/2017/11/21/oauth2-php/ https://blog.csdn.net/halsonhe/article/details/81 ...
- 对OAuth2.0协议的理解和测试demo
1. 什么是OAuth OAuth(开放授权)是一个开放标准,允许用户授权第三方网站访问他们存储在另外的服务提供者上的信息,而不需要将用户名和密码提供给第三方网站或分享他们数据的所有内容. OAuth ...
- 第三方登录,一般都是遵循OAuth2.0协议。
1. QQ登录OAuth2.0协议开发流程 1.1 开发流程 申请接入,获取appid和appkey; 开发应用,设置协作者账号,上线之前只有协作者才能进行第三方登录 放置QQ登录按钮(这个自己可以用 ...
- Oauth2.0协议曝漏洞 大量社交网站隐私或遭泄露
2014年是IT业界不平常的一年,XP停服.IE长老漏洞(秘狐)等等层出不穷,现在,社交网络也爆出惊天漏洞:Oauth2.0协议漏洞 继OpenSSL漏洞后,开源安全软件再曝安全漏洞.新加坡南洋理工大 ...
- 接口测试工具-Jmeter使用笔记(八:模拟OAuth2.0协议简化模式的请求)
背景 博主的主要工作是测试API,目前已经用Jmeter+Jenkins实现了项目中的接口自动化测试流程.但是马上要接手的项目,API应用的是OAuth2.0协议授权,并且采用的是简化模式(impli ...
- 轻松搭建CAS 5.x系列(6)-在CAS Server上增加OAuth2.0协议
概述说明 CAS Server默认搭建出来,客户端程序只能按照CAS自身的协议接入.CAS的强大在于,有官方的插件,可以支持其他的协议.本章节就让CAS Server怎么增加OAuth2.0的登录协议 ...
- 《OAuth2.0协议安全形式化分析-》----论文摘抄整理
---恢复内容开始--- 本篇论文发表在计算机工程与设计,感觉写的还是很有水准的.实验部分交代的比较清楚 本篇论文的创新点: 使用Scyther工具 主要是在 DY模型下面 形式化分析了 OAuth2 ...
- Spring Security 实战干货: 简单的认识 OAuth2.0 协议
1.前言 欢迎阅读 Spring Security 实战干货 系列文章 .OAuth2.0 是近几年比较流行的授权机制,对于普通用户来说可能每天你都在用它,我们经常使用的第三方登录大都基于 OAuth ...
- 理解OAuth2.0协议和授权机制
无论是自然资源还是互联网上的资源,需要控制使用权与被使用权,以保护资源的安全.合理的使用和有效的管控. 项目中,我们需要控制的是用户资源,既要保证有效用户的合理使用,又要防范非法用户的攻击.如此,如何 ...
随机推荐
- 【RL系列】On-Policy与Off-Policy
强化学习大致上可分为两类,一类是Markov Decision Learning,另一类是与之相对的Model Free Learning 分为这两类是站在问题描述的角度上考虑的.同样在解决方案上存在 ...
- Linux(Contos7.5)环境搭建之Linux远程登录(一)
1.下载<putty-0.70cn.zip>工具包 2.解压到适合的文件夹下
- 创建image
摘要: 本节演示如何通过 Web GUI 和 CLI 两种方法创建 Image. 本节演示如何通过 Web GUI 和 CLI 两种方法创建 Image. OpenStack 为终端用户提供了 Web ...
- Python 装饰器Decorator(一)
(一) 装饰器基础知识 什么是Python装饰器?Python里装饰器是一个可调用的对象(函数),其参数是另一个函数(被装饰的函数) 假如有一个名字为somedecorator的装饰器,target是 ...
- uc浏览器的用户体验
用户界面: 我认为,uc浏览器的用户界面还是很招人喜欢的,可以很容易让用户找到自己想看的网页.简单快捷. 记住用户的选择: uc在每次用户访问完网站之后都会记住用户访问的高频网站,以便下次用户可以更好 ...
- BIND的安装配置
简介 bind是dns协议的一种实现,也就是说,bind仅仅是实现DNS协议的一种应用程序 bind运行后的进程名叫named,不叫bind bind bind的配置文件在:/etc/named.co ...
- 201621123037 《Java程序设计》第4周学习总结
#Week04-面向对象设计与继承 1. 本周学习总结 1.1 写出你认为本周学习中比较重要的知识点关键词 关键词:超级父类."is-a".父类.子类.重载.继承.多态 1.2 尝 ...
- 【beta】Scrum站立会议第5次....11.7
小组名称:nice! 组长:李权 成员:于淼 刘芳芳韩媛媛 宫丽君 项目内容:约跑app(约吧) 时间:2016.11.7 12:00——12:30 地点:传媒西楼220室 本次对beta阶段的 ...
- laravel5.6 调用第三方类库
大概流程: 1. 新建一个目录方类库 2. 配置composer配置文件 3. 在项目中使用终端运行composer dumpautoload 4. 使用时 方法调用可以new对象后->方法名 ...
- mybatis 批量插入 返回主键id
我们都知道Mybatis在插入单条数据的时候有两种方式返回自增主键: 1.对于支持生成自增主键的数据库:增加 useGenerateKeys和keyProperty ,<insert>标签 ...