用 Node 实现 tiktok 授权登录

一、 前言

最近公司在做 tiktok 授权登录的需求, 其实对前端来说。这个活儿非常简单, 点一下按钮,调一下接口,剩下的都是后端干了,经常不知道里面的具体实现细节与原理,而且面试如果能把这里业务讲明白也是很加分的点, 对于我们自己来说也是很有意思的一件事, 所以在评审前,我就先一步用node将后端的这块逻辑给他掉通了,等他在开发的时候就可以来问我了

效果如下:

二、文档

因为tiktok在国内的使用是受限制的, 所以需要使用科学上网工具, 有需要的可以滴滴我, 然后最重要的就是看文档, 纯英文文档看着还是很容易犯困的, 可以下载一个 DeepL 的翻译浏览器插件, 还是非常好用, 点击链接查看文档

三、步骤

写代码之前先要搞明白我们要干的事。 以及步骤, 其实类似这种授权的,基本都是一个套路, 大致分为以下几个步骤

  1. 开发者平台上创建账号,获取 key 密钥 填写授权时候的一些信息与授权成功的回调地址
  2. 通过 key等参数 重定向到授权页面, 获取到授权成功的 code 等信息
  3. 通过 拿到的 code 等调用 token 接口登录, 获取到 access_token, access_token 非常重要,成功获取到 access_token 后,就有权限去调用后面接口了
  4. 我们调用一个 用户信息接口, 测试一下是否调用成功

四、代码

写代码前先在平台上新建 app manage 后面会用到, 注意回调地址 必须是 https 的地址, 拿到授权成功的 code 后会跳到这个回调到 https://kalodata.com/tiktok/ 这个地址,并且在地址上携带

新建一个express node 应用

js 复制代码
npm init -y
npm i express node-fetch cookie-parser cors body-parser -S

基本框架如下:

js 复制代码
const express = require("express");
const app = express();
const fetch = require("node-fetch");
const cookieParser = require("cookie-parser");
const cors = require("cors");
const bodyParser = require("body-parser");

app.use(cookieParser());
app.use(cors());
app.listen(process.env.PORT || 5001);
app.use(bodyParser.urlencoded({ extended: true }));

const CLIENT_KEY = "zxxxxxxx";
const CLIENT_SECRET = "ddddddddd";
const SERVER_ENDPOINT_REDIRECT = "回调地址";

// 1、通过令牌获取 code
app.get("/oauth", (req, res) => {
  //...
});

// 2、通过 code 去获取 access_token Fetch an access token using an authorization code
app.get("/tiktok", (req, res) => {
  const { code, scopes, state } = req.query;
  //...
});

// 3、通过access_token 获取用户信息
const getUserInfo = async (access_token) => {
  //...
};

1. 通过令牌获取 code

js 复制代码
app.get("/oauth", (req, res) => {
  const csrfState = Math.random().toString(36).substring(2);
  res.cookie("csrfState", csrfState, { maxAge: 60000 });
  let url = "https://www.tiktok.com/v2/auth/authorize/";
  // the following params need to be in `application/x-www-form-urlencoded` format.
  url += `?client_key=${CLIENT_KEY}`;
  url += "&scope=user.info.basic";
  url += "&response_type=code";
  url += `&redirect_uri=${SERVER_ENDPOINT_REDIRECT}`;
  url += "&state=" + csrfState;
  res.redirect(url);
});

打开浏览器输入 http://localhost:5001/oauth 调用这个接口时, 浏览器会进行重定向调转请求 https://www.tiktok.com/v2/auth/authorize/ 参数类型是application/x-www-form-urlencoded 格式, 需要注意的是 此授权接口,与下一个获取access_token接口需要保证一致。为了安全防止拦截误导, 需要增加一个 csrfState 校验, 通过state参数传递, 并在传递到的下一个接口内验证是否一致

2、通过 code 获取 access_token

js 复制代码
 const { code, scopes, state } = req.query;
  let url = "https://open.tiktokapis.com/v2/oauth/token/";
  const formData = new URLSearchParams();
  formData.append("client_key", CLIENT_KEY);
  formData.append("client_secret", CLIENT_SECRET);
  formData.append("code", code);
  formData.append("grant_type", "authorization_code");
  formData.append("redirect_uri", SERVER_ENDPOINT_REDIRECT);
  // data.append('code_verifier', 'Required for mobile app only'); APP 端使用
  fetch(url, {
    method: "POST",
    body: formData.toString(),
    headers: { "Content-Type": "application/x-www-form-urlencoded" },
  })
    .then((response) => {
      if (response.ok) {
        return response.json();
      }
      throw new Error("POST request failed");
    })
    .then(async (responseData) => {
      if (responseData.access_token) {
       console.log(responseData.access_token)  // 获取到 access_token
      }
    })
    .catch((error) => {
      console.error(error);
   });

这里需要注意回调回来的是线上地址, 需要手动将地址的 host 改成本地, localhost:5001/tiktok?code=xxx 在这个路由拿到回调回来的code 等参数, 可以在此验证 csrfstate, 调用 https://open.tiktokapis.com/v2/oauth/token/ 接口,构造 application/x-www-form-urlencoded 类型的参数进行请求,即可拿到 access_token

3、获取用户信息

获取用户信息有新旧两个版本, 我用的是 v2 的版本。这个地方需要注意的点还是比较多的,首先这个接口基于 OAuth 2.0 规范中的 Bearer Token 的授权类型, 其次请求成功后,得到的结果是一个 Gunzip 类型的压缩类型, 开始想通过解压没有发现很好的方式, 然后搜索时发现只需要 转化成 res.text() 即可, 解决链接

js 复制代码
const getUserInfo = async (access_token) => {
  const bearer_access_token = `Bearer ${access_token}`;
  let url = `https://open.tiktokapis.com/v2/user/info/?fields=avatar_url,union_id,open_id,display_name`;
  return fetch(url, {
    method: "GET",
    headers: {
      Authorization: bearer_access_token,
    },
  })
    .then((res) => res.text())
    .catch((error) => {
      console.log(error, "error");
    });
};

五、总结

本文主要讲了实现tiktok登录授权的思路与接口的一些注意的点, 各种平台的授权机制都大体类似, 可以说一通百通, 很多时候作为前端我们是不会涉及到这些内容, 但是对于想要了解这里面的原理,又是绕不开点, 授权大体上经过两个步骤, 通过key 换 code, 通过 code 换取 access_token, 因为access_token 非常重要而且有有效期, 为了增加安全性和用户体验, 经常需要使用 refresh_token 去更新 access_token, refresh_token 一般拥有更长的有效期, 可以在 access_token 过期时自动更新, 既避免了用户频繁进行身份验证,又提高了系统的可用性和用户体验

tip: 直接拉长access_token 可以吗? 答: 是一种方式,但是不是最佳实践,会产生三个问题, 1、有效期延长意味着令牌存在更长的时间窗口用于滥用、泄漏、或被攻击者滥用 2、撤销和失效问题: 撤销权限或者设备丢失,想让access_token立刻失效将变得困难,并且用户权限更新等问题和反馈等问题将没有那么及时

相关推荐
hhcccchh3 分钟前
学习vue第八天 Vue3 模板语法和内置指令 - 简单入门
前端·vue.js·学习
yyf198905256 分钟前
Vue 框架相关中文文献
前端·javascript·vue.js
粥里有勺糖12 分钟前
开发一个美观的 VitePress 图片预览插件
前端·vue.js·vitepress
superman超哥17 分钟前
Rust HashSet与BTreeSet的实现细节:集合类型的底层逻辑
开发语言·后端·rust·编程语言·rust hashset·rust btreeset·集合类型
陟上青云31 分钟前
一篇文章带你搞懂原型和原型链
前端
我的写法有点潮31 分钟前
推荐几个国外比较流行的UI库(上)
前端·javascript·css
鹏多多37 分钟前
jsx/tsx使用cssModule和typescript-plugin-css-modules
前端·vue.js·react.js
superman超哥1 小时前
Rust String与&str的内部实现差异:所有权与借用的典型案例
开发语言·后端·rust·rust string·string与str·内部实现·所有权与借用
ssshooter1 小时前
复古话题:Vue2 的空格间距切换到 Vite 后消失了
前端·vue.js·面试
IamZJT_2 小时前
拒绝做 AI 的“饲养员” ❌:前端程序员在 AI 时代的生存与进化指南 🚀
前端·ai编程