用 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立刻失效将变得困难,并且用户权限更新等问题和反馈等问题将没有那么及时

相关推荐
码事漫谈16 分钟前
VS Code 1.107 更新:多智能体协同与开发体验升级
后端
码事漫谈31 分钟前
从概念开始开始C++管道编程
后端
@淡 定34 分钟前
Spring中@Autowired注解的实现原理
java·后端·spring
前端一小卒35 分钟前
一个看似“送分”的需求为何翻车?——前端状态机实战指南
前端·javascript·面试
syt_101338 分钟前
Object.defineProperty和Proxy实现拦截的区别
开发语言·前端·javascript
遝靑42 分钟前
Flutter 跨端开发进阶:可复用自定义组件封装与多端适配实战(移动端 + Web + 桌面端)
前端·flutter
cypking1 小时前
Web前端移动端开发常见问题及解决方案(完整版)
前端
老前端的功夫1 小时前
Vue 3 vs Vue 2 深度解析:从架构革新到开发体验全面升级
前端·vue.js·架构
栀秋6661 小时前
深入浅出链表操作:从Dummy节点到快慢指针的实战精要
前端·javascript·算法
serendipity_hky1 小时前
【go语言 | 第2篇】Go变量声明 + 常用数据类型的使用
开发语言·后端·golang