资讯专栏INFORMATION COLUMN

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

Acceml / 2570人阅读

摘要:本文讲解的就是授权登录的教程。从拿到的用户信息如下图最终效果参与文章如何设计第三方授权登录的用户表第三方授权登录的时候,第三方的用户信息是存数据库原有的表还是新建一张表呢答案这得看具体项目了,做法多种,请看下文。

需求:在网站上想评论一篇文章,而评论文章是要用户注册与登录的,那么怎么免去这麻烦的步骤呢?答案是通过第三方授权登录。本文讲解的就是 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 个步骤:

web 端重定向 http://github.com/login/oauth...

根据 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; 

代码参考 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


// 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 拿到的用户信息如下图:

最终效果:

参与文章:

https://www.jianshu.com/p/a9c...

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

具体代码实践请参考文章:

1. 第三方登录用户信息表设计

2. 浅谈数据库用户表结构设计,第三方登录

4. 最后
笔者的 github 博客地址:https://github.com/biaochenxuying/blog

如果您觉得这篇文章不错或者对你有所帮助,请给个赞或者星呗,你的点赞就是我继续创作的最大动力。

全栈修炼 有兴趣的朋友可以扫下方二维码关注我的公众号

我会不定期更新有价值的内容,长期运营。

关注公众号并回复 福利 可领取免费学习资料,福利详情请猛戳: Python、Java、Linux、Go、node、vue、react、javaScript

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/102342.html

相关文章

  • python实现微信三方网站扫码登录(Django)

    摘要:写在前面本周刚在项目中实现了微信第三方网站扫码登录。准备与注意事项微信公众平台跟微信开放平台是两个不同的平台,别搞混了。参数在微信开放平台中查看。 写在前面 本周刚在项目中实现了微信第三方网站扫码登录。因为第一次写相关项目,所以遇到了很多坑。所以写这篇文章是希望像我之前那样的小白也能从容的开发,不要浪费无谓的时间,这篇文章尽量写的详细简单。准备与注意事项 微信公众平台跟微信开放平台是...

    lemanli 评论0 收藏0
  • 基于 github issues 实现三方评论系统

    摘要:什么是第三方评论系统博客或系统,一般都是有内容和评论两部分组成。而且垃圾评论和过滤非法关键字难度较大,所以在国内外都有第三评论系统。三评论系统实现预备工作创建。 本文只是介绍如何基于 github issues 实现第三方评论系统,对于 Hexo 介绍,本文并不打算详述,如果有童鞋之前还没有了解 Hexo 的,可以先看一下之前文章《静态博客框架 Hexo 入门 》,或者直接访问 Hex...

    waltr 评论0 收藏0
  • Authing 是什么及实现了哪些国际身份协议

    摘要:是什么提供身份认证和授权服务。你希望你的用户能使用微信登录,同时你还希望能追踪到用户的注册来源,活动数据,以便你做后续的用户增长。 Authing 是什么? Authing 提供身份认证和授权服务。 我们为开发者和企业提供用以保证应用程序安全所需的认证模块,这让开发人员无需成为安全专家。 你可以将以任意语言和任意技术栈编写的应用接入到 Authing,同时你还可以自定义应用程序的登录方...

    RichardXG 评论0 收藏0
  • 详解 Github App 玩法

    摘要:之前在使用搭建博客平台的时候,研究过一番如何取得授权并调用的办法。后来经过研究,总算找到了这种更为优雅的办法。网站通过上的授权码往取回。要完成上述的流程,首先必须先注册一个。此时通过授权的仓库都可以被用户通过进行读写操作了。 showImg(https://segmentfault.com/img/remote/1460000019343854?w=1200&h=600); 之前在使用...

    LoftySoul 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<