昆仑虚 GitHub 登录实现 🔥

引言

在开始之前我们先模拟以下场景:

  • 用户 张三GitHub 注册了账号, 并存储了个人的信息(头像、昵称、性别、邮箱、手机号……)
  • 这时 张三 访问不知名应用 A, A 想要 张三 可以免注册、登录, 可以直接从 GitHub 上获取到 张三 的个人信息, 然后进行注册、登录
  • 那么问题来了, 要想实现上面 👆🏻 这个需求, GitHub 作为服务商要做哪些事情呢? A 应用又要做哪些事件呢? 作为用户 张三 他的交互流程又该是怎样的呢?

一、OAuth2 是什么?

在这里我先不直接抛出概念, 请允许我从引言中的模拟场景出发, 来发表下我个人对 OAuth2 的理解:

  • OAuth2 就是一个标准、约定
  • 它规定 一个应用 要想获取用户在 另一个应用 里的个人信息, 需要怎样的一个流程
  • 以及各个角色(用户、应用端、授权服务器、资源服务器)之间需要进行怎样的通信、交互的, 最后又是如何完成用户授权功能
  • 所谓 用户授权 简单来讲就是, 用户允许将 资源服务器 的个人信息 授权应用端, 让 应用端 能够获取到自己在 资源服务器 的个人信息

现在我们看下 维基 上的解释:

  • OAuth 全称是 Open Authentication(开放授权), 是一个开放标准, 它允许 用户第三方应用 具有访问该用户在某一网站上存储的个人信息的权限, 而无需将用户名和密码提供给第三方应用

  • OAuth 允许用户提供一个令牌, 而不是用户名和密码来访问他们存放在特定服务提供者的数据。每一个令牌授权一个特定的网站 (例如, 视频编辑网站) 在特定的时段 (例如, 接下来的 2 小时内) 内访问特定的资源 (例如仅仅是某一相册中的视频)。这样, OAuth 让用户可以授权第三方网站访问他们存储在另外服务提供者的某些特定信息, 而非所有内容

二、交互流程

首选在开始介绍 交互流程 之前我们先来了解下整个过程需要涉及到的几个角色:

  • 资源所有者 (Resource Owner): 顾名思义, 资源的所有者, 就是上文提到的用户
  • 应用程序 (Client): 准备访问用户资源的应用程序, 可以是任何应用端
  • 授权服务器 (Authorization Server): 授权服务器, 在获取用户的同意授权后, 颁发访问令牌给应用程序
  • 资源服务器 (Resource Server): 保存用户资源的服务

下面我们以 GitHub 为例来讲解下 OAuth 授权的交互流程, 当一个应用接入了 GitHubOAuth 后, 用户从授权到登录整个交互流程应该是怎样的:

  • 用户访问 A 网站, 并选择 GitHub 登录成功
  • A 网站将跳转到 GitHub 让用户进行授权
  • 这时 GitHub 将会先验证用户的身份, 用户如果没有登录则需要先进行登录, 然后询问用户是否授权给 A 网站
  • 用户同意授权后 GitHub 将会重定向回 A 网站, 同时会在 URL 上携带一个 授权码
  • A 网站就可以使用 授权码, 向 GitHub 授权服务器 获取访问 资源服务器token(权限)
  • GitHub 授权服务器 返回 资源服务器 token
  • A 网站使用 资源服务器 token, 向 GitHub资源服务器 请求用户数据

昆仑虚 GitHub 登录实现 🔥

补充: 第三方登录, 实质就是 OAuth 授权, 用户想要登录 A 网站, 但又不想注册登录想直接使用 第三方系统身份数据 进行登录

三、「GitHub 授权 OAuth 应用」实现

理论简单过下, 接下来我们就按照上文给出的流程图, 来完成 GitHub 第三方登录授权登录功能, 当然更多的细节可以查阅 官方文档

3.1 创建应用

首先如果我们想要使用 GitHub 第三方网站 OAuth 授权, 需要先去 GitHub 上进行登记, 这里可以直接访问 applications/new 进行登记

昆仑虚 GitHub 登录实现 🔥

登记成功后, 将进入应用详情页面, 在详情页我们可以看到 GitHub 为我们登记的应该生成了一个唯一 ID, 这里我们可以简单记下, 后面我们进行 GitHub 授权等操作都需要用到

昆仑虚 GitHub 登录实现 🔥

同时这里我们还需要创建一个 client_secret(客户端秘钥) 在后面向 授权服务 获取访问 资源服务器 token 需要该秘钥

昆仑虚 GitHub 登录实现 🔥

创建 client_secret(客户端秘钥) 成功后记得保存下生成的秘钥, 刷新后将无法再次查看秘钥内容了

昆仑虚 GitHub 登录实现 🔥

到此应用登记也就结束咯, 同时我们可以通过访问 settings/developers 来查看所有已经登记的应用

3.2 用户授权

改造登录页, 新增跳转到 GitHub 授权入口, 用户点击下列 👇 授权按钮 将跳转到 https://github.com/login/oauth/authorize? client_id=6aa8689e618b1e87e483 进行授权, 其中 6aa8689e618b1e87e483 是我们上面创建的 应用 ID

昆仑虚 GitHub 登录实现 🔥

用户进行登录、授权

昆仑虚 GitHub 登录实现 🔥

3.3 后端「授权登录」实现

上面 👆🏻 授权成功后, 将会重定向到我们登记应用时所填写的路由, 这里我填写的是
后端的一个 api, 该接口逻辑如下:

昆仑虚 GitHub 登录实现 🔥

  1. 拿到接口携带的 授权码 获取 资源服务器 token
import qs from 'qs';
const { code } = ctx.request.query;

const { data: { access_token } } = await axios({
  method: 'post',
  url: `https://github.com/login/oauth/access_token?${qs.stringify({
    code,
    client_id: clientID,
    client_secret: clientSecret,
  })}`,
  headers: {
    accept: 'application/json',
  },
});
  1. 通过 资源服务器 token 获取用户信息
const { data } = await axios({
  method: 'get',
  url: 'https://api.github.com/user',
  headers: {
    accept: 'application/json',
    Authorization: `token ${access_token}`,
  },
});
  1. 根据 GitHub 用户 ID 查找当前用户是否登录过, 如果没有则创建新用户
// 根据 githubId 查找用户
let { data: user } = await findOne({
  model: 'User',
  search: { githubId: githubInfo.id },
});

// 查不到用户, 则进行注册
if (!user) {
  const { change: [newUser] } = await create({
    model: 'User',
    body: [{
      name: githubInfo.name,
      githubId: githubInfo.id,
      account: githubInfo.login,
    }],
  });

  user = newUser;
}
  1. 登录(设置 cookie)
// 拿到 id、name、account 创建 jwt token
const token = await signJwt({
  id: user.id,
  name: user.name,
  account: user.account,
});
// 设置 cookie
ctx.cookies.set('jwt_token', token, { maxAge: 1000 * 60 * 60 * 24 * 7 };
  1. 最后重定向回首页
ctx.status = 302;
ctx.redirect('http://www.dev.kunlunxu.cc');

到此整个大致流程基本也就结束咯, 下面 👇🏻 是最终的一个效果

昆仑虚 GitHub 登录实现 🔥

这是最后新建的用户表

昆仑虚 GitHub 登录实现 🔥

四、总结

本文到此也就结束咯, 文中内容相对比较简单, 只是简单记录了下 昆仑虚 接入 GitHub 第三方登录的一个流程, 以及过程中遇到的一些疑惑, 当然如果你对 昆仑虚 感兴趣欢迎 👏🏻 点个 star

五、参考

原文链接:https://juejin.cn/post/7230469903123185719 作者:墨渊君

(0)
上一篇 2023年5月8日 上午10:20
下一篇 2023年5月8日 上午10:31

相关推荐

发表回复

登录后才能评论