为了账号安全,请及时绑定邮箱和手机立即绑定

如何在React中搭建一个Telegram认证Hook(一步步教你)

制作React Hook来验证Telegram用户(一步一步教程)

嘿!👋 你有没有想过为你的应用自定义一个身份验证钩子?特别是针对 Telegram 吗?如果你正在 Telegram 平台上构建一些酷炫的东西,比如我的应用 代码优化 (稍后再详谈),你可能想要以一种无缝的方式管理你的用户。

在本文中,我来告诉你如何创建一个用于处理认证的 React 钩子,使用 Telegram 的 SDK。

基于什么选择Telegram的SDK?

Telegram 有一个很酷的功能,用户可以通过 Telegram 本身登录,只需点击一下就可以获取他们的详细信息。这里的好处是,你不必担心复杂的 OAuth 认证流程。这种登录方式快速、简单且高度安全。结合使用 React hooksSupabase(用于用户管理),你可以很快搞定认证。

好了,准备好了吗?让我们潜水吧! 🏊‍♂️
步骤 1:设置钩子

我们先从构建一个钩子开始,在 React 中,钩子就是用来复用有状态逻辑的工具。目标是通过 Telegram 的 SDK 获取用户信息并将其存入我们应用的全局状态。下面就是基本设置:

    import { useEffect, useCallback } from 'react';  
    import { useLaunchParams } from '@telegram-apps/sdk-react';  
    import { useUserStore } from '@/store/userStore';  

    const useAuth = () => {  
      const lp = useLaunchParams(); // 从 Telegram 获取启动参数 lp  

      const setUser = useUserStore((state) => state.setUser); // 全局用户管理状态  
      const setIsNewUser = useUserStore((state) => state.setIsNewUser); // 新用户标志  
      const existingUserInState = useUserStore((state) => state.user); // 获取现有的用户信息  

      // 此处将添加更多功能  
      return { user: existingUserInState };  
    };  

    export default useAuth;
发生了什么事?
  1. **useLaunchParams**:这是来自 @telegram-apps/sdk-react 包的一个钩子。它允许我们获取当有人通过 Telegram 启动你的应用时发送的用户信息。并将这些信息存储在变量 lp 中。
  2. 全局状态管理:我们使用全局存储(如 useUserStore)来管理用户数据。这使得应用可以在需要的地方获取用户信息,保持代码的整洁。我使用 Zustand 来管理状态,但你也可以用 ReduxContext API 或其他任何状态管理方案来替代它。
步骤 2:搞定用户注册过程

现在已经从Telegram拿到了用户的数据,需要将这些数据存储到我们的数据库中(这里我使用的是Supabase)。不想在已有用户数据的情况下重复获取。这时就可以用上缓存机制和useCallback钩子了。

我们给新用户增加一些逻辑处理吧

    const signUpUser = useCallback(async () => {  
      const initDataResult = lp.initData;  
      const user = initDataResult?.user as AuthUser | undefined;  

      // 如果从Telegram的启动参数中获取到了用户数据  
      if (user) {  
        // 如果用户已经在状态中存在,避免不必要的数据库查询  
        if (existingUserInState && existingUserInState.id === user.id) {  
          console.log('用户已经在状态中存在,跳过重新查询');  
          return;  
        }  

        try {  
          // 检查用户是否已经在数据库中存在  
          const { data: existingUser, error: fetchError } = await supabase  
            .from('users')  
            .select('*')  
            .eq('id', user.id)  
            .single();  

          // 处理查询错误  
          if (fetchError) {  
            console.error('检索用户时出错:', fetchError);  
            return;  
          }  

          // 如果没有找到用户,则创建新用户  
          if (!existingUser) {  
            setIsNewUser(true);  

            const { data, error } = await supabase  
              .from('users')  
              .insert([  
                {  
                  ...user,  
                  current_level: 1,  
                  coins: 1000,  
                  boosts: [{ Freeze: 10, Hint: 10 }],  
                },  
              ])  
              .select()  
              .single();  

            if (error) {  
              console.error('插入用户数据时出错:', error);  
            } else {  
              console.log('用户已注册:', data);  
              setUser(data); // 更新全局状态为新用户  
            }  
          } else {  
            console.log('找到现有用户:', existingUser);  
            setUser(existingUser);  
            setIsNewUser(false);  
          }  
        } catch (error) {  
          console.error('用户注册过程中出现问题:', error);  
        }  
      }  
    }, [lp, setUser, setIsNewUser, existingUserInState]);
简单来说:
  1. 备忘录useCallback 钩子确保 signUpUser 函数不会在每次渲染时重新创建,这有助于提升性能。
  2. 检查现有用户:如果用户已经在我们的全局状态中(通过 existingUserInState 检查),我们将跳过数据库调用。这可以节省不必要的 API 请求。
  3. 数据库检查:如果用户在 Supabase 中不存在,我们会为他们创建一个新条目,附带一些初始数据,比如 coinscurrent_levelboosts
第 3 步:在应用启动时触发注册。

现在我们希望用户在打开应用时自动登录。我们将使用 useEffect 钩子在组件加载时触发登录过程。

    useEffect(() => {  
      signUpUser(); // 组件挂载时自动注册用户  
    }, [signUpUser]);
这是它为什么有效:
  • useEffectuseEffect 钩子确保注册流程仅在组件首次加载时执行一次。依赖数组中的 [signUpUser] 确保只有当 signUpUser 函数发生变化时才会调用,得益于 useCallback 的功能。
第 4 步:把用户从钩子中拉回来

最后,我们从我们的钩子返回用户,这样使用这个钩子的任何组件都可以获取当前用户数据。

返回 { user: existingUserInState };
完整的代码:

下面就是完整的 useAuth 钩子,用于认证。

    import { useEffect, useCallback } from 'react';  
    import supabase from '@/supabaseClient';  
    import { useUserStore } from '@/store/userStore';  
    import { AuthUser } from '@/context/UserContext/interface';  
    import { useLaunchParams } from '@telegram-apps/sdk-react';  

    const useAuth = () => {  
      const lp = useLaunchParams();  
      const setUser = useUserStore((state) => state.setUser);  
      const setIsNewUser = useUserStore((state) => state.setIsNewUser);  
      const existingUserInState = useUserStore((state) => state.user);  

      const signUpUser = useCallback(async () => {  
        const initDataResult = lp.initData;  
        const user = initDataResult?.user as AuthUser | undefined;  

        if (user) {  
          if (existingUserInState && existingUserInState.id === user.id) {  
            console.log('用户已在状态中,跳过重新获取');  
            return;  
          }  

          try {  
            const { data: existingUser, error: fetchError } = await supabase  
              .from('users')  
              .select('*')  
              .eq('id', user.id)  
              .single();  

            if (fetchError) {  
              console.error('获取用户错误:', fetchError);  
              return;  
            }  

            if (!existingUser) {  
              setIsNewUser(true);  

              const { data, error } = await supabase  
                .from('users')  
                .insert([  
                  {  
                    ...user,  
                    current_level: 1,  
                    coins: 1000,  
                    boosts: [{ Freeze: 10, Hint: 10 }],  
                  },  
                ])  
                .select()  
                .single();  

              if (error) {  
                console.error('插入用户错误:', error);  
              } else {  
                console.log('用户注册成功:', data);  
                setUser(data);  
              }  
            } else {  
              console.log('用户已存在:', existingUser);  
              setUser(existingUser);  
              setIsNewUser(false);  
            }  
          } catch (error) {  
            console.error('用户注册过程中错误:', error);  
          }  
        }  
      }, [lp, setUser, setIsNewUser, existingUserInState]);  

      useEffect(() => {  
        signUpUser();  
      }, [signUpUser]);  

      return { user: existingUserInState };  
    };  

    export default useAuth;
如何帮助我们优化代码

代码提升(Code Boost)是指优化和增强代码的过程。以下是如何帮助我们在代码提升中获益的方法。

Code Boost 中,我们使用这个具体的钩子来通过 Telegram 管理用户认证。当用户打开应用,钩子会检查他们在数据库中是否已经存在。若不存在,则会自动注册,获得一些初始金币和游戏助推来开始使用。这一切都通过 Telegram SDK 和我们的 useAuth 钩子无缝完成。

Code Boost

⚡️如果你正在搭建类似的东西,欢迎查看Telegram中的Code Boost。这个钩子让你集成Telegram认证变得非常简单,现在你可以在自己的项目中轻松使用它!

⚡️闪电启动:点击这里

编程愉快!
点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号

举报

0/150
提交
取消