github 授权登录教程与如何设计第三方授权登录的用户表

需求:在网站上想评论一篇文章,而评论文章是要用户注册与登录的,那么怎么免去这麻烦的步骤呢?答案是通过第三方授权登录。本文讲解的就是 github 授权登录的教程。
效果体验地址:http://biaochenxuying.cn
1. github 第三方授权登录教程
先来看下 github 授权的完整流程图 1:

或者看下 github 授权的完整流程图 2:

1.1 申请一个 OAuth App
首先我们必须登录上 github 申请一个 OAuth App,步骤如下:
- 登录 github
- 点击头像下的 Settings -> Developer settings 右侧 New OAuth App
- 填写申请 app 的相关配置,重点配置项有2个
- Homepage URL 这是后续需要使用授权的 URL ,你可以理解为就是你的项目根目录地址
- Authorization callback URL 授权成功后的回调地址,这个至关重要,这是拿到授权 code 时给你的回调地址。
具体实践如下:
- 首先登录你的 GitHub 账号,然后点击进入Settings。

- 点击 OAuth Apps , Register a new application 或者 New OAuth App 。

- 输入信息。

- 应用信息说明。

流程也可看 GitHub 设置的官方文档-Registering OAuth Apps。
1.2 授权登录
github 文档:building-oauth-apps/authorizing-oauth-apps
授权登录的主要 3 个步骤:
- 根据 code 获取 access_token
- 根据 access_token 获取用户信息
笔者这次实践中,项目是采用前后端分离的,所以第 1 步在前端实现,而第 2 步和第 3 步是在后端实现的,因为第 2 个接口里面需要Client_secret 这个参数,而且第 3 步获取的用户信息在后端保存到数据库。
1.3 代码实现
1.3.1 前端
笔者项目的技术是 react。
// config.js
// ***** 处请填写你申请的 OAuth App 的真实内容
const config = {
'oauth_uri': 'https://github.com/login/oauth/authorize',
'redirect_uri': 'http://biaochenxuying.cn/',
'client_id': '*****',
'client_secret': '*******',
};
// 本地开发环境下
if (process.env.NODE_ENV === 'development') {
config.redirect_uri = "http://localhost:3001/"
config.client_id = "******"
config.client_secret = "*****"
}
export default config;
redirect_uri 回调地址是分环境的,所以我是新建了两个 OAuth App 的,一个用于线上生产环境,一个用于本地开发环境。
一般来说,登录的页面应该是独立的,对应相应的路由 /login , 但是本项目的登录 login 组件是 nav 组件的子组件,nav 是个全局用的组件, 所以回调地址就写了 http://biaochenxuying.cn/。
- 所以点击跳转是写在 login.js 里面;
- 授权完拿到 code 后,是写在 nav.js 里面
- nav.js 拿到 code 值后去请求后端接口,后端接口返回用户信息。
- 其中后端拿到 code 还要去 github 取 access_token ,再根据 access_token 去取 github 取用户的信息。
// login.js
// html
<Button
style={{ width: '100%' }}
onClick={this.handleOAuth} >
github 授权登录
</Button>
// js
handleOAuth(){
// 保存授权前的页面链接
window.localStorage.preventHref = window.location.href
// window.location.href = 'https://github.com/login/oauth/authorize?client_id=***&redirect_uri=http://biaochenxuying.cn/'
window.location.href = `${config.oauth_uri}?client_id=${config.client_id}&redirect_uri=${config.redirect_uri}`
}
// nav.js
componentDidMount() {
// console.log('code :', getQueryStringByName('code'));
const code = getQueryStringByName('code')
if (code) {
this.setState(
{
code
},
() => {
if (!this.state.code) {
return;
}
this.getUser(this.state.code);
},
);
}
}
componentWillReceiveProps(nextProps) {
const code = getQueryStringByName('code')
if (code) {
this.setState(
{
code
},
() => {
if (!this.state.code) {
return;
}
this.getUser(this.state.code);
},
);
}
}
getUser(code) {
https
.post(
urls.getUser,
{
code,
},
{ withCredentials: true },
)
.then(res => {
// console.log('res :', res.data);
if (res.status === 200 && res.data.code === 0) {
this.props.loginSuccess(res.data);
let userInfo = {
_id: res.data.data._id,
name: res.data.data.name,
};
window.sessionStorage.userInfo = JSON.stringify(userInfo);
message.success(res.data.message, 1);
this.handleLoginCancel();
// 跳转到之前授权前的页面
const href = window.localStorage.preventHref
if(href){
window.location.href = href
}
} else {
this.props.loginFailure(res.data.message);
message.error(res.data.message, 1);
}
})
.catch(err => {
console.log(err);
});
}
1.3.2 后端
笔者项目的后端采用的技术是 node.js 和 express。
- 后端拿到前端传来的 code 后,还要去 github 取 access_token ,再根据 access_token 去取 github 取用户的信息。
- 然后把要用到的用户信息通过 注册 的方式保存到数据库,然后返回用户信息给前端。
// app.config.js
exports.GITHUB = {
oauth_uri: 'https://github.com/login/oauth/authorize',
access_token_url: 'https://github.com/login/oauth/access_token',
// 获取 github 用户信息 url // eg: https://api.github.com/user?access_token=******&scope=&token_type=bearer
user_url: 'https://api.github.com/user',
// 生产环境
redirect_uri: 'http://biaochenxuying.cn/',
client_id: '*****',
client_secret: '*****',
// // 开发环境
// redirect_uri: "http://localhost:3001/",
// client_id: "*****",
// client_secret: "*****",
};
// 路由文件 user.js
const fetch = require('node-fetch');
const CONFIG = require('../app.config.js');
const User = require('../models/user');
// 第三方授权登录的用户信息
exports.getUser = (req, res) => {
let { code } = req.body;
if (!code) {
responseClient(res, 400, 2, 'code 缺失');
return;
}
let path = CONFIG.GITHUB.access_token_url;
const params = {
client_id: CONFIG.GITHUB.client_id,
client_secret: CONFIG.GITHUB.client_secret,
code: code,
};
// console.log(code);
fetch(path, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(params),
})
.then(res1 => {
return res1.text();
})
.then(body => {
const args = body.split('&');
let arg = args[0].split('=');
const access_token = arg[1];
// console.log("body:",body);
console.log('access_token:', access_token);
return access_token;
})
.then(async token => {
const url = CONFIG.GITHUB.user_url + '?access_token=' + token;
console.log('url:', url);
await fetch(url)
.then(res2 => {
console.log('res2 :', res2);
return res2.json();
})
.then(response => {
console.log('response ', response);
if (response.id) {
//验证用户是否已经在数据库中
User.findOne({ github_id: response.id })
.then(userInfo => {
// console.log('userInfo :', userInfo);
if (userInfo) {
//登录成功后设置session
req.session.userInfo = userInfo;
responseClient(res, 200, 0, '授权登录成功', userInfo);
} else {
let obj = {
github_id: response.id,
email: response.email,
password: response.login,
type: 2,
avatar: response.avatar_url,
name: response.login,
location: response.location,
};
//注册到数据库
let user = new User(obj);
user.save().then(data => {
// console.log('data :', data);
req.session.userInfo = data;
responseClient(res, 200, 0, '授权登录成功', data);
});
}
})
.catch(err => {
responseClient(res);
return;
});
} else {
responseClient(res, 400, 1, '授权登录失败', response);
}
});
})
.catch(e => {
console.log('e:', e);
});
};
至于拿到 github 的用户信息后,是注册到 user 表,还是保存到另外一张 oauth 映射表,这个得看自己项目的情况。
从 github 拿到的用户信息如下图:

最终效果:

参与文章:
2. 如何设计第三方授权登录的用户表
第三方授权登录的时候,第三方的用户信息是存数据库原有的 user 表还是新建一张表呢 ?
答案:这得看具体项目了,做法多种,请看下文。
第三方授权登录之后,第三方用户信息一般都会返回用户唯一的标志 openid 或者 unionid 或者 id,具体是什么得看第三方,比如 github 的是 id
- 1. 直接通过 注册 的方式保存到数据库
第一种:如果网站 没有 注册功能的,直接通过第三方授权登录,授权成功之后,可以直接把第三的用户信息 注册 保存到自己数据库的 user 表里面。典型的例子就是 微信公众号的授权登录。
第二种:如果网站 有 注册功能的,也可以通过第三方授权登录,授权成功之后,也可以直接把第三的用户信息 注册 保存到自己数据库的 user 表里面(但是密码是后端自动生成的,用户也不知道,只能用第三方授权登录),这样子的第三方的用户和原生注册的用户信息都在同一张表了,这种情况得看自己项目的具体情况。笔者的博客网站暂时就采用了这种方式。
- 2. 增加映射表
现实中很多网站都有多种账户登录方式,比如可以用网站的注册 id 登录,还可以用手机号登录,可以用 QQ 登录等等。数据库中都是有映射关系,QQ、手机号等都是映射在网站的注册 id 上。保证不管用什么方式登录,只要去查映射关系,发现是映射在网站注册的哪个 id 上,就让哪个 id 登录成功。
- 3. 建立一个 oauth 表,一个 id 列,记录对应的用户注册表的 id
建立一个 oauth 表,一个 id 列,记录对应的用户注册表的 id,然后你有多少个第三方登陆功能,你就建立多少列,记录第三方登陆接口返回的 openid;第三方登陆的时候,通过这个表的记录的 openid 获取 id 信息,如果存在通过 id 读取注册表然后用 session 记录相关信息。不存在就转向用户登陆/注册界面要用户输入本站注册的账户进行 openid 绑定或者新注册账户信息进行绑定。
具体代码实践请参考文章:
4. 最后
笔者的 github 博客地址:github
如果您觉得这篇文章不错或者对你有所帮助,请给个赞或者星呗,你的点赞就是我继续创作的最大动力。
github 授权登录教程与如何设计第三方授权登录的用户表的更多相关文章
- 【转】【Android应用开发详解】第01期:第三方授权认证(一)实现第三方授权登录、分享以及获取用户资料
转载请注明出处:http://blog.csdn.net/yangyu20121224/article/details/9057257 由于公司项目的需要,要实现在项目中使用第三方授权登录以及分享文字 ...
- Android实战简易教程-第二十四枪(基于Baas的用户表查询功能实现!)
接着上一篇,我们注冊了几个用户,用户表例如以下: 以下我们用ListView将表中数据显示出来吧. 首先看一下main.xml: <RelativeLayout xmlns:android=&q ...
- 使用ShareSDK实现第三方授权登录、分享以及获取用户资料效果,项目中包含:源码+效果图+项目结构图
[Android应用开发详解]第01期:第三方授权认证(一)实现第三方授权登录.分享以及获取用户资料 由于公司项目的需要,要实现在项目中使用第三方授权登录以及分享文字和图片等这样的效果,几经波折, ...
- mysql 用户表结构设计,第三方登录
说起用户表,大概是每个应用/网站立项动工(码农们)考虑的第一件事情.用户表结构的设计,算是整个后台架构的基石.如果基石不稳,待到后面需求跟进了发现不能应付,回过头来反复修改用户表,要大大小小作改动的地 ...
- 拎壶带你冲----教育类mysql用户表设计参考
说起用户表,大概是每个应用/网站立项动工(码农们)考虑的第一件事情.用户表结构的设计,算是整个后台架构的基石.如果基石不稳,待到后面需求跟进了发现不能应付,回过头来反复修改用户表,要大大小小作改动的地 ...
- Github 第三方授权登录教程
Github 第三方授权登录教程 ####大致流程图 ####1.首先注册一个github帐号,Applications>Developer applications>Register a ...
- SPA+.NET Core3.1 GitHub第三方授权登录 使用AspNet.Security.OAuth.GitHub
GitHub第三方授权登录 使用SPA+.NET Core3.1实现 GitHub第三方授权登录 类似使用AspNet.Security.OAuth.GitHub,前端使用如下:VUE+Vue-Rou ...
- 【Demo】QQ,github,微博第三方社交登录
本文主要讲解 集成 第三方社交账号登录 为什么会有这个需求? 主要是因为目前互联网的网站数量太多,如果在各个站点都注册一个账号 用户非常不容易记住每个账号的用户名和密码,并且非常难保证每个账号的密码足 ...
- 【Android应用开发详解】实现第三方授权登录、分享以及获取用户资料
由于公司项目的需要,要实现在项目中使用第三方授权登录以及分享文字和图片等这样的效果,几经波折,查阅了一番资料,做了一个Demo.实现起来的效果还是不错的,不敢独享,决定写一个总结的教程,供大家互相 ...
随机推荐
- dubbo是如何控制并发数和限流的?
ExecuteLimitFilter ExecuteLimitFilter ,在服务提供者,通过 的 "executes" 统一配置项开启: 表示每服务的每方法最大可并行执行请求数 ...
- Java | Map排序,工具类改进
package util; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; ...
- JVM运行时数据区--深入理解Java虚拟机 读后感
程序计数器 程序计数器是线程私有的区域,很好理解嘛~,每个线程当然得有个计数器记录当前执行到那个指令.占用的内存空间小,可以把它看成是当前线程所执行的字节码的行号指示器.如果线程在执行Java方法,这 ...
- 如何获取app中的toast
前言 Toast是什么呢?在这个手机飞速发展的时代,app的种类也越来越多,那们在日常生活使用中,经常会发现,当你在某个app的输入框输入非法字符或者非法执行某个流程时,经常看到系统会给你弹出一个黑色 ...
- exe、dos、bat等静默运行,后台运行,不弹窗的解决办法
exe中 #pragma comment( linker, "/subsystem:windows /entry:mainCRTStartup" ) 1. WinExec(LPCS ...
- 聊一聊 SpringBoot 自动配置的原理
解析思路 我们建立好一个SpringBoot的工程后,我们将从启动类,SpringBootApplication开始进行探究. 开始解析 首先我们建立一个 Springboot的工程.找到启动类,我们 ...
- 100天搞定机器学习|day43 几张GIF理解K-均值聚类原理
前文推荐 如何正确使用「K均值聚类」? KMeans算法是典型的基于距离的聚类算法,采用距离作为相似性的评价指标,即认为两个对象的距离越近,其相似度就越大.该算法认为簇是由距离靠近的对象组成的,因此把 ...
- c# 读取 txt 文件中数据(int)
今天在学图的算法做测试是,需要读取文本文件中的点坐标,本来很简单的事情,折腾了半天,记录一下找到的一种简单粗暴的解决方法,以便以后查看. 第一种方法 : StringReader string lin ...
- Apex 获取真正的IP地址
代码如下 declare l_ip varchar2(15); begin if OWA_UTIL.GET_CGI_ENV('X-FORWARDED-FOR') is not null then l_ ...
- vue 异步加载远程组件(支持编译less语法)
本代码已组件化,可以直接使用. 说明:本组件可以直接解析.vue文件,为了支持less语法解析,在组件中引入less.js,可在less官网下载. 组件代码 <template> < ...