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

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

1. github 第三方授权登录教程


先来看下 github 授权的完整流程图 1:


微信图片_20220513141822.png


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


微信图片_20220513141836.png


1.1 申请一个 OAuth App


首先我们必须登录上 github 申请一个 OAuth App,步骤如下:


  1. 登录 github
  2. 点击头像下的 Settings -> Developer settings 右侧 New OAuth App
  3. 填写申请 app 的相关配置,重点配置项有2个
  4. Homepage URL 这是后续需要使用授权的 URL ,你可以理解为就是你的项目根目录地址
  5. Authorization callback URL 授权成功后的回调地址,这个至关重要,这是拿到授权 code 时给你的回调地址。


具体实践如下:


  1. 首先登录你的 GitHub 账号,然后点击进入Settings。


微信图片_20220513141856.png


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


微信图片_20220513141910.png


  1. 输入信息。


微信图片_20220513141923.png


  1. 应用信息说明。


微信图片_20220513141937.png


流程也可看 GitHub 设置的官方文档-Registering OAuth Apps


1.2 授权登录


github 文档:building-oauth-apps/authorizing-oauth-apps

授权登录的主要 3 个步骤:


  1. web 端重定向 http://github.com/login/oauth...
  2. 根据 code 获取 access_token
  3. 根据 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;


代码参考 config.js


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}`
}


代码参考 login.js


// 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);
      });
  }


参考 nav.js


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: "*****",
};


代码参考 app.config.js


// 路由文件  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);
    });
};


代码参考 user.js


至于拿到 github 的用户信息后,是注册到 user 表,还是保存到另外一张 oauth 映射表,这个得看自己项目的情况。


从 github 拿到的用户信息如下图:


微信图片_20220513142122.png


最终效果:


微信图片_20220513142136.gif


参与文章:


  1. https://www.jianshu.com/p/a9c...
  2. https://blog.csdn.net/zhuming...


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 绑定或者新注册账户信息进行绑定。


相关文章
|
5月前
|
Ubuntu Linux Shell
github用存在的私钥在Linux上配置免密登录
在Linux上配置GitHub免密登录,使用已有的私钥。系统环境为Ubuntu 22.04.3 LTS。步骤包括:1) 将名为`github`的私钥文件上传至`~/.ssh/github`;2) 设置正确权限`chmod 600 ~/.ssh/github`和`chmod 700 ~/.ssh`;3) 启动SSH代理并添加私钥`ssh-agent -s`和`ssh-add ~/.ssh/github`。完成上述步骤后,可以无缝使用GitHub。
73 0
|
1月前
|
程序员
github登录+注册方法
github登录+注册方法
90 0
|
3月前
|
存储 Linux Go
如何在Github上Pull Request的教程
关于如何在GitHub上发起Pull Request(合并请求)的详细教程,包括Fork(分支)、Clone(克隆)、创建新分支、修改代码、提交更改、推送到远程仓库等步骤,并提供了解决权限问题的方法,如创建个人访问令牌(Personal Access Token)。
109 6
|
3月前
|
数据采集 数据可视化 Ruby
GitHub星标破万!Python学习教程(超详细),真的太强了!
Python 是一门初学者友好的编程语言,想要完全掌握它,你不必花上太多的时间和精力。 Python 的设计哲学之一就是简单易学,体现在两个方面: 1. 语法简洁明了:相对 Ruby 和 Perl,它的语法特性不多不少,大多数都很简单直接,不玩儿玄学。 2. 切入点很多:Python 可以让你可以做很多事情,科学计算和数据分析、爬虫、Web 网站、游戏、命令行实用工具等等等等,总有一个是你感兴趣并且愿意投入时间的。
怎样在GitHub上建立仓库、以及怎样实现分支代码的合并。保姆级别的教程
这篇文章是一份详细的GitHub使用教程,介绍了如何在GitHub上创建仓库、创建分支、编辑和发布更改内容、发起拉取请求以及合并分支的操作步骤。
怎样在GitHub上建立仓库、以及怎样实现分支代码的合并。保姆级别的教程
|
3月前
|
SQL 运维 安全
GitHub爆赞的Web安全防护指南,网络安全零基础入门必备教程!
web安全现在占据了企业信息安全的很大一部分比重,每个企业都有对外发布的很多业务系统,如何保障web业务安全也是一项信息安全的重要内容。 然而Web 安全是一个实践性很强的领域,需要通过大量的练习来建立对漏洞的直观认识,并积累解决问题的经验。 Web安全与防护技术是当前安全界关注的热点,今天给小伙伴们分享的这份手册尝试针对各类漏洞的攻防技术进行体系化整理,从漏洞的原理到整体攻防技术演进过程进行详细讲解,从而形成对漏洞和web安全的体系化的认识。
|
3月前
|
SQL 运维 安全
GitHub爆赞的Web安全防护指南,网络安全零基础入门必备教程!
web安全现在占据了企业信息安全的很大一部分比重,每个企业都有对外发布的很多业务系统,如何保障web业务安全也是一项信息安全的重要内容。 然而Web 安全是一个实践性很强的领域,需要通过大量的练习来建立对漏洞的直观认识,并积累解决问题的经验。 Web安全与防护技术是当前安全界关注的热点,今天给小伙伴们分享的这份手册尝试针对各类漏洞的攻防技术进行体系化整理,从漏洞的原理到整体攻防技术演进过程进行详细讲解,从而形成对漏洞和web安全的体系化的认识。
|
3月前
|
数据安全/隐私保护
【Azure Developer】Github Action使用Azure/login@v1插件登录遇见错误的替代方案
【Azure Developer】Github Action使用Azure/login@v1插件登录遇见错误的替代方案
|
3月前
|
存储
【Azure Developer】Github Action部署资源(ARM模板)到Azure中国区时,遇见登录问题的解决办法
【Azure Developer】Github Action部署资源(ARM模板)到Azure中国区时,遇见登录问题的解决办法
|
4月前
|
网络协议 Unix Linux
网安人必须人手一份的《Linux私房教程》,GitHub星标286K!
Linux是一套免费使用和自由传播的操作系统内核,是一个基于POSIX和Unix的多用户、多任务支持多线程和多CPU的操作系统内核。它能运行主要的Unix工具软件、应用程序和网络协议。它支持32位和64位硬件。Linux继承了Unix以网络为核心的设计思想,是一个性能稳定的多用户网络操作系统内核。 作为网络安全的初学者,Linux基础知识和常用命令是我们的必备技能,我们不能只会操作Windows相关的工具。一方面很多网站都是基于Linux环境搭建,比如LAMP,其安全性更好;另一方面,很多命令或工具都集成在了Linux相关环境中,比如Kali等。 今天给小伙伴们分享一份Linux私房教程,这份
下一篇
无影云桌面