English 简体中文 繁體中文 한국 사람 日本語 Deutsch русский بالعربية TÜRKÇE português คนไทย french

简体中文 繁體中文 English 日本語 Deutsch 한국 사람 بالعربية TÜRKÇE คนไทย Français русский

回答

收藏

Telegram小程序 指南 | 授权用户

开源社区 开源社区 9394 人阅读 | 0 人回复 | 2025-02-19

本帖最后由 riyad 于 2025-2-21 19:27 编辑
/ E: m' \& K/ l- I# \1 k7 C5 I: Y0 s" g1 _6 M4 Q( F. i* ]

本文提供了不同编程语言的代码示例,说明开发人员如何使用 Telegram 初始数据授权用户。

: X. @8 F+ J0 x1 g1 d. u
客户端

首先,需要从客户端向服务器传输初始数据开始。 我们可以使用此代码 :

  1. import { retrieveLaunchParams } from '@telegram-apps/sdk';
    ! V: c: R, U. \- C9 V0 g! k
  2. ! k, C& r$ L. Z; p3 r' z0 C
  3. const { initDataRaw } = retrieveLaunchParams();! O' m: ]3 u( L, H8 t

  4. # f9 r5 {) Z) B, P3 N. S
  5. fetch('https://example.com/api', {% F$ ?* }# e7 w: n
  6.   method: 'POST',
    . T- A' u) ?3 @$ M+ J1 m
  7.   headers: {9 l/ S* ~9 ~  t7 E- k0 e( F# [
  8.     Authorization: `tma ${initDataRaw}`( r) R3 L+ q( {% O: h" l$ X
  9.   },# J8 A2 E$ y0 r- y  W0 c
  10. });
复制代码

我们使用 https://example.com/api URL 向假想的服务器发送请求。 该请求使用 HTTP POST 方法(你可以使用任何你想要的方法),并附加 Authorization(授权)标头,这在这里是最重要的。 表示一个字符串,包含由空格分割的两个部分。 第一个描述授权方法(在 的情况下,我们的服务器将支持其他几种方法),第二个包含授权数据。 就 Telegram Mini Apps 而言,第二部分是原始 init 数据。


' f3 m% c2 f, R# U服务器端

现在,当 init 数据传输到服务器端时,我们应该创建一个简单的 HTTP 服务器,使用这些数据并 授权用户。

Node.js

Node.js 示例使用 express 处理 HTTP 请求。

  1. import { validate, parse, type InitDataParsed } from '@telegram-apps/init-data-node';  a/ Q1 y$ J9 G7 `/ k( e  v
  2. import express, {3 @1 `' I+ X! N+ u+ Z8 A+ K# P
  3.   type ErrorRequestHandler,& G" n# U( L; j8 U& R
  4.   type RequestHandler,6 i: Z% o+ U% e5 w- Q+ _, Z
  5.   type Response,% k/ b, h, }* T# K
  6. } from 'express';, k3 c1 f1 z1 [
  7. 9 v* s* E' f5 X1 ~0 f
  8. /**
    . b: x* s: C5 f
  9. * Sets init data in the specified Response object.3 L% t' s. e, I  r) R5 ]3 f9 R- E
  10. * @param res - Response object.
    # \/ D0 x, @; O) g0 `
  11. * @param initData - init data.% \, `' `* x4 U0 T  E5 o
  12. */
    2 Z- o3 a7 j# b! l
  13. function setInitData(res: Response, initData: InitDataParsed): void {9 e0 ]! z7 y+ j2 u
  14.   res.locals.initData = initData;
    5 K) E( e7 q- F2 C" _
  15. }
    % x4 T9 V, F6 i& E
  16. ; q5 F) ]/ r6 S3 L/ x, b: ]
  17. /**/ `5 J; v) u0 D! ^0 @
  18. * Extracts init data from the Response object.6 j- g" n, V! T6 f% }8 N
  19. * @param res - Response object.% O0 B  t, K6 a6 W
  20. * @returns Init data stored in the Response object. Can return undefined in case,, a/ w! l3 y( R
  21. * the client is not authorized.
    : ]) h6 B2 x1 S
  22. */2 Z7 N9 o+ K0 E
  23. function getInitData(res: Response): InitDataParsed | undefined {
    3 ]# M( ]! w! R' y
  24.   return res.locals.initData;
    $ K$ f: O3 x7 V$ Q2 I
  25. }
    ! r! D0 F: w2 [  p5 S# x

  26. ; c' y9 F- r( V, @2 D' x" s4 N
  27. /**) }0 K. V) h$ I. q2 ^1 q8 x/ q
  28. * Middleware which authorizes the external client.
    0 ~9 W2 J' B1 o/ J
  29. * @param req - Request object.
    7 A: t3 [8 G+ t9 y" E. n' W! ]" B
  30. * @param res - Response object.. n; `  @# D9 U
  31. * @param next - function to call the next middleware.) H/ v* [6 @3 \1 S& r# V
  32. */( U2 y  |6 x5 \# y* y+ j% n) j
  33. const authMiddleware: RequestHandler = (req, res, next) => {% g0 X  W. S/ P3 V+ `3 \) h
  34.   // We expect passing init data in the Authorization header in the following format:' `! M+ G* j- v% u. ]9 S
  35.   // <auth-type> <auth-data>6 G7 U1 E8 F& D# k8 S# J- h; j
  36.   // <auth-type> must be "tma", and <auth-data> is Telegram Mini Apps init data.
    ) B) F/ m8 J+ }  Y' i* _9 S" o
  37.   const [authType, authData = ''] = (req.header('authorization') || '').split(' ');
    3 Z( w4 q2 J$ P/ {8 g( \. M! ~
  38. . O9 c. [. g1 Y. O1 O
  39.   switch (authType) {9 U3 q7 [% J7 l3 \$ P$ T
  40.     case 'tma':
    : Y$ z# I, z) U! p, a! ]
  41.       try {7 O! F* h- l' E$ }' Y
  42.         // Validate init data.
    ) e0 F. K5 j# [9 I' T  |+ p& f
  43.         validate(authData, token, {6 t6 V# c" N/ y7 ~& p
  44.           // We consider init data sign valid for 1 hour from their creation moment./ O7 C0 K. m6 ^* y9 X( \" K
  45.           expiresIn: 3600,
    ' d( }4 r* B, `: y+ i
  46.         });3 I8 f1 Z0 D9 [

  47. + @/ z9 n6 B' ~2 m4 q. _4 |0 G1 S
  48.         // Parse init data. We will surely need it in the future.
    ) h, x1 ^8 k: A( ?" t
  49.         setInitData(res, parse(authData));; A8 c" R! S* \- ], R9 U. Z9 R3 W. B
  50.         return next();9 G5 x& \" w- b% n- M8 U
  51.       } catch (e) {
    + P3 y7 Z+ h4 h
  52.         return next(e);9 y2 Y( y% r9 j3 ^/ P( W
  53.       }$ J7 c& D2 L7 E! |, V
  54.     // ... other authorization methods.* _# p4 e- x* y. k; Q+ f0 C+ q
  55.     default:
    2 v6 O# H- Z) l7 n) p, W6 M, H' V
  56.       return next(new Error('Unauthorized'));
    ! V7 w- K0 |0 B+ C& h7 l
  57.   }
      K1 l, Y6 S$ U
  58. };; T0 l6 A" ~' N, _0 n
  59. ( o0 A4 F9 l5 \) K
  60. /**7 r' C3 q7 v" }5 p
  61. * Middleware which shows the user init data.' R* p) c8 n9 K: `* |. Q  \4 Y
  62. * @param _req# ?( @! U5 v6 U6 \! X8 s: y: C+ V
  63. * @param res - Response object.: W( R6 |! s: r/ i# q. e, H
  64. * @param next - function to call the next middleware.1 \6 n* X( g; a
  65. */
    ) f6 }% c# G* @2 k- |& Y& `% V
  66. const showInitDataMiddleware: RequestHandler = (_req, res, next) => {
    2 M) H; f/ e  ~. t( x
  67.   const initData = getInitData(res);
    ! z- t& z* k8 Y5 X& o
  68.   if (!initData) {
    " k' v. ]2 Q+ ~
  69.     return next(new Error('Cant display init data as long as it was not found'));2 s3 ~9 ]' ]8 c" ?
  70.   }
    * Q) a. K3 j1 N: ]9 J1 b3 ^
  71.   res.json(initData);
    9 w; o8 H$ X' j
  72. };
    2 ~/ g+ J8 l$ U0 ~0 e/ i
  73. # K: H; m! i  [9 m" z; v% q  C
  74. /**. W$ l+ U1 q& b, v3 _/ ^; M
  75. * Middleware which displays the user init data.
    ' C# C$ J6 |9 Y0 s) C: J
  76. * @param err - handled error.* a8 _1 E7 P2 V# Z) q, p- [
  77. * @param _req9 X) k. \9 a* g% k4 N
  78. * @param res - Response object.9 o% ~2 S: y/ \* K) j% R
  79. */
    + _# g; y# m0 a( c3 y
  80. const defaultErrorMiddleware: ErrorRequestHandler = (err, _req, res) => {
    5 ~1 `: \: y5 F$ {: g/ T/ b
  81.   res.status(500).json({5 G! U* x0 ]0 ]/ v) [9 m: m% s9 Y
  82.     error: err.message,  ~+ v6 c5 [/ k6 z8 ]! P( \# f
  83.   });' ]; M; Z' t& O' i' r8 `! z) g
  84. };. ~* g& d" E0 R' a, x* W' E

  85. & V& R' q. W5 h
  86. // Your secret bot token.
    4 I; K% s. p: P" C
  87. const token = '1234567890:ABC';
    ; `8 C/ E. G  _6 T) e
  88. ) B$ j8 x- _9 z, _# }
  89. // Create an Express applet and start listening to port 3000.+ \4 |) V) e. v+ a8 r9 Y
  90. const app = express();
    - Y- Z; e4 O; @: t6 g

  91. & M( L8 g/ w2 J2 v- N" r
  92. app.use(authMiddleware);
    ; \7 f2 ?4 V" U
  93. app.get('/', showInitDataMiddleware);
    % e" Z8 o+ C$ h$ }) P/ a+ V+ m
  94. app.use(defaultErrorMiddleware);
    5 m4 _) q2 s3 [: ^: B
  95. 1 ~, y8 o; a& O% K7 k( P  A) N
  96. app.listen(3000);' L" J9 B7 X! o- r

  97. ' ~7 v7 ~# M5 e, ^
  98. // After the HTTP server was launched, try sending an HTTP GET request to the URL
    / ]1 ]3 C$ ~: E( i. @0 p
  99. // http://localhost:3000/ with an Authorization header containing data in the required format.
复制代码

6 M) k4 @' }0 r9 Q  r, ^GoLang[color=var(--vp-c-brand-1)]

GoLang 示例使用 [color=var(--vp-c-brand-1)]gin 处理 HTTP 请求。

  1. package main
    $ e$ X6 S4 U! I7 ?

  2. ! W& \4 G2 a, X4 N
  3. import (0 E/ d6 Q( ~) U
  4.         "context"! n8 z/ \, F; B) f/ x4 w
  5.         "strings"
    ; A- e  S) b$ F, I" d  T! K7 C
  6.         "time"
    % o- t8 E( P) J& T- k3 h5 g: [9 g

  7. ) J& [. U9 G3 h$ u/ p& b/ D
  8.         "github.com/gin-gonic/gin", R- m7 ^- h( t- h* q8 O& F$ V* i7 H
  9.         initdata "github.com/telegram-mini-apps/init-data-golang"  e6 J+ l% w4 o3 ?/ `
  10. )
    4 Y, d* X' U# @) {4 [" O; t6 F! D

  11. / `7 k. Y3 E' H) P; o0 F5 b
  12. type contextKey string4 p6 G8 }" R& I8 @8 p) O

  13. ' W7 ~" T) S0 h- q. x
  14. const (
    0 t; S" c$ d) s/ m  }
  15.         _initDataKey contextKey = "init-data"% d) ?9 D5 d& g1 ]; ^! A4 Y" g
  16. )1 B2 x- |% w2 P, K# Z
  17. & B4 o/ r- w9 \* |" Z5 ]1 t
  18. // Returns new context with specified init data.
    4 i/ u* y- P' p" u* t
  19. func withInitData(ctx context.Context, initData initdata.InitData) context.Context {  I" `2 \6 |4 I  r% p
  20.         return context.WithValue(ctx, _initDataKey, initData)) C, ^! l# P& p# v5 O0 U6 N
  21. }: P4 e7 b. ~0 q) v/ [- m) w& Q3 ?
  22. ! b" f! D/ h- w+ F; r" m( H# n
  23. // Returns the init data from the specified context.
    : U! L# r6 n+ ]/ e( o9 G4 _% P2 \
  24. func ctxInitData(ctx context.Context) (initdata.InitData, bool) {
    0 v" \6 b' M) t* o1 a3 p; a
  25.         initData, ok := ctx.Value(_initDataKey).(initdata.InitData)
    * k$ z, ?8 ^4 U/ r
  26.         return initData, ok/ k3 u! b/ x# e3 ^5 Y+ c7 q$ A
  27. }6 s  c0 J9 ]0 H% ~
  28. 0 ~+ t+ W! J# B1 O) j& H/ a( Q
  29. // Middleware which authorizes the external client.( P' u, `) ~3 ^; u7 C- d" W1 s* V: [
  30. func authMiddleware(token string) gin.HandlerFunc {- o; w6 d* P9 @3 d+ P( u
  31.         return func(context *gin.Context) {
    0 J8 ^8 D- i; u  \) [3 r& d
  32.                 // We expect passing init data in the Authorization header in the following format:
    0 |) G6 U7 P; R  j" n5 @7 ^
  33.                 // <auth-type> <auth-data>
    . `' M6 H2 X3 b1 V0 M$ [
  34.                 // <auth-type> must be "tma", and <auth-data> is Telegram Mini Apps init data./ m  H, @$ R" r' ^( Z
  35.                 authParts := strings.Split(context.GetHeader("authorization"), " ")5 T1 d3 n, l, y4 c
  36.                 if len(authParts) != 2 {8 I+ D* N9 F% G( {& |6 l3 v
  37.                         context.AbortWithStatusJSON(401, map[string]any{
    : D$ |* D- n* x5 J) g4 y& {+ k
  38.                                 "message": "Unauthorized",8 R/ h/ c! Y1 x- _' B4 P7 e8 y$ m
  39.                         })
    8 _6 Q4 I# H4 _# k6 F" U' |4 N3 X
  40.                         return6 j' F+ P* p% u
  41.                 }
    : C0 w) _3 c. U7 i

  42. 4 E( |3 {) S) L9 w5 a
  43.                 authType := authParts[0]
    $ ~7 K# T6 R  E7 t( f( D
  44.                 authData := authParts[1]
    - Z2 R- t: Q3 i6 S. w

  45. 5 ^4 N7 z: j1 y- s
  46.                 switch authType {
    ; N3 h/ ?( ]8 P7 x
  47.                 case "tma":
    5 X2 o) }+ R) `0 P( ~2 M6 ?0 p6 v
  48.                         // Validate init data. We consider init data sign valid for 1 hour from their
    * E! i, `3 I# Y+ C! @
  49.                         // creation moment.
    ) @: ]- S1 ]' g7 x
  50.                         if err := initdata.Validate(authData, token, time.Hour); err != nil {4 t5 r+ R5 s6 o5 T! A! I& s
  51.                                 context.AbortWithStatusJSON(401, map[string]any{: V) h: q( f  i4 S
  52.                                         "message": err.Error(),: `% ?$ p3 ^$ U+ S6 [% t
  53.                                 })* a) f. `! y8 {; B
  54.                                 return
    , U* o+ N3 K3 P/ X
  55.                         }% g5 {- r# a) R! u0 F

  56. 7 O$ g+ P0 E. N5 |; r* L, J
  57.                         // Parse init data. We will surely need it in the future.* k# F0 D% x$ D% C' W/ P+ J6 J
  58.                         initData, err := initdata.Parse(authData)# Q* N1 K9 _3 e8 j! `, b% S
  59.                         if err != nil {( @, r8 r! F1 i$ z- U. Z4 W
  60.                                 context.AbortWithStatusJSON(500, map[string]any{' n1 t* g, f- D2 B) X6 o
  61.                                         "message": err.Error(),
    " C  i8 m: {% h$ \: @
  62.                                 })
    " s4 E' W  H; L; c" Z3 w
  63.                                 return
    8 c8 m# E. f4 \4 s- e- _! `8 J1 E
  64.                         }
    5 Y8 ~( |9 Z7 t2 c) L# q; V
  65. 4 d- W' ?1 K, ^
  66.                         context.Request = context.Request.WithContext(6 d6 P" O5 H* X( S5 D
  67.                                 withInitData(context.Request.Context(), initData),/ g. `) H2 g# \
  68.                         )# {/ Q" x( J8 c) \: [
  69.                 }4 w5 N7 x6 {* ^8 q. K6 y0 ~/ G
  70.         }
    ' B9 Z" z3 F7 i+ N4 E7 o7 l
  71. }9 `9 b* Q- I6 N. h
  72. & H: \2 L: m1 O2 }1 ~, P
  73. // Middleware which shows the user init data.3 k1 ]4 D5 n$ N0 F. u  |* D( {
  74. func showInitDataMiddleware(context *gin.Context) {/ H0 H  B0 B7 S. R4 I6 L! M$ o' Q2 e3 h
  75.         initData, ok := ctxInitData(context.Request.Context())
    ( |  `1 l+ m) {
  76.         if !ok {
    5 O% G# q1 a( `0 W# Q5 q4 h
  77.                 context.AbortWithStatusJSON(401, map[string]any{
    $ M* C. c) r7 K7 w) Q8 W
  78.                         "message": "Init data not found",
    9 k: `6 ]; H4 ]$ O
  79.                 })
    , e- P. C& W. ^: R+ L& e3 B* j
  80.                 return! l0 H/ k" D  z
  81.         }
    7 U* q' T+ ]0 }: a; M/ C+ B
  82. 8 J) u; w4 @5 W4 e1 J$ W
  83.         context.JSON(200, initData)
    " |/ [8 ^! ~- R6 Y' {% R, b5 J
  84. }1 A! ~0 {+ B; C+ T. W. V) s4 n
  85. ; r( f; R5 @$ p
  86. func main() {6 u( D$ ^2 F; W) a. g: I
  87.         // Your secret bot token.
    % O! D8 u& a5 Z
  88.         token := "1234567890:ABC"
    ' d" X' ]! s; n  U7 a0 k

  89. / P1 o6 T3 B- T& b+ U" B' J
  90.         r := gin.New()$ Z' l8 z. G" b/ t( \" X; J3 l

  91. $ j8 E* _6 n6 }* p3 P6 b
  92.         r.Use(authMiddleware(token))6 J. Q( n. `9 j! G! X
  93.         r.GET("/", showInitDataMiddleware)5 b3 B8 I1 [- C
  94. 2 L2 W# T& N5 C0 e$ f0 A5 |0 k4 l
  95.         if err := r.Run(":3000"); err != nil {% V! ]  F: f. p- z
  96.                 panic(err)
    4 [& @/ U+ k' S" C( |5 h
  97.         }
    , m% A6 m& v# i& L$ z9 o! g
  98. }
复制代码
3 L, a# L8 X3 S

2 }9 A" [1 F1 k1 B  d$ j- A0 G9 r
分享到:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则