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

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

回答

收藏

Telegram小程序 指南 | 授权用户

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

本帖最后由 riyad 于 2025-2-21 19:27 编辑
, e2 E! |/ ^- S/ t8 [2 J5 t! q& P

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


3 k# b5 x1 H3 L: T' P' p, t客户端

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

  1. import { retrieveLaunchParams } from '@telegram-apps/sdk';
    ( i+ l( w. b$ I) C
  2. ( u4 U0 `4 r) D& j$ F0 H% S7 U
  3. const { initDataRaw } = retrieveLaunchParams();7 d/ H- C7 p5 m+ _; k1 ?9 L5 M8 ^
  4. 7 T+ {4 i6 o& C( \* f) r' z) a
  5. fetch('https://example.com/api', {
      H7 D  U# T- t" O1 y1 B
  6.   method: 'POST',. A5 Q4 h5 _$ |/ F
  7.   headers: {9 H, j- B2 r0 F
  8.     Authorization: `tma ${initDataRaw}`
    ' y4 T1 e0 x6 Y( B+ _; \
  9.   },
    ; D5 E' I! I% f* `
  10. });
复制代码

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


  }- x3 x8 j( F4 M$ k4 K2 f2 Q* o服务器端

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

Node.js

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

  1. import { validate, parse, type InitDataParsed } from '@telegram-apps/init-data-node';
    1 w  @; h5 P3 W; W# f8 F
  2. import express, {
    . _1 H+ ]; A/ ?3 K, k3 ^- N
  3.   type ErrorRequestHandler,. |& A7 W5 o6 z5 }* u
  4.   type RequestHandler,
    ' I! W! B# L$ w$ r& _: N+ O
  5.   type Response," ]. Z; o3 ?, F2 J3 W7 ~
  6. } from 'express';/ _9 n8 C# _4 j' S, _) j* @
  7. 1 l, @" i2 Z3 M
  8. /**
    : ^( G# p: x$ h& i, A' Z" e: c1 p
  9. * Sets init data in the specified Response object.
    3 E9 m) \& N" ?! f( a( e6 @
  10. * @param res - Response object.6 ?2 E  D  o' |- W$ Z/ ?
  11. * @param initData - init data.
    ) }6 M8 D5 T+ h2 c- P" C: O- L( h
  12. */
    8 D; H* \5 x7 z4 I+ U1 i6 L- u
  13. function setInitData(res: Response, initData: InitDataParsed): void {2 n% E7 E" s/ ]3 N: S8 O+ u
  14.   res.locals.initData = initData;' Z. d1 \. \1 B" m& m2 s
  15. }6 |( Q4 K0 E  D: O
  16. / z: z/ W8 O+ ]' T$ h  ]
  17. /**
    6 e4 ~# Z% N; H3 j7 s
  18. * Extracts init data from the Response object.7 ^2 J6 W& X8 m
  19. * @param res - Response object.
    . X1 O0 p) j; e, [. ?% j% u8 [
  20. * @returns Init data stored in the Response object. Can return undefined in case,4 W9 Q" G- O- C6 l2 ~
  21. * the client is not authorized.3 K* h+ m' q8 d
  22. */
    & d) Y+ A9 v3 T+ |, n6 ~
  23. function getInitData(res: Response): InitDataParsed | undefined {1 _; {! |% `) u# Y, m, K0 d! _0 E  H0 G
  24.   return res.locals.initData;
    9 @2 A1 X& a! s# B- b/ C* D
  25. }
    2 u+ V8 Y# J: B
  26. : {: K& s& `: b2 G
  27. /**
    3 h* y! C" z9 h; O
  28. * Middleware which authorizes the external client.# i1 a4 w9 m$ \& S  K! o7 j
  29. * @param req - Request object.
    $ z8 |3 ?' P  r
  30. * @param res - Response object.
    # `2 m- C9 z( j# ^4 @; U
  31. * @param next - function to call the next middleware.0 f. Z$ @" z$ _8 W& y/ S/ c# S
  32. */
    1 {, c% U: p) ~1 h# ~
  33. const authMiddleware: RequestHandler = (req, res, next) => {
    . @& }4 E, K3 K* f$ Y
  34.   // We expect passing init data in the Authorization header in the following format:0 {& [  Z1 b5 X5 ^" b6 f
  35.   // <auth-type> <auth-data>1 {  o2 O% a' T& f- _  F
  36.   // <auth-type> must be "tma", and <auth-data> is Telegram Mini Apps init data.+ ]0 T5 G2 W1 n' Z
  37.   const [authType, authData = ''] = (req.header('authorization') || '').split(' ');% U/ ?$ k0 K& L  u

  38. . U' t' J4 y0 K8 F
  39.   switch (authType) {
    - X2 S) _. s, [/ r/ r
  40.     case 'tma':; q' ^+ ]1 C, W" U3 t
  41.       try {
    4 s- O. j' P9 J6 ~2 P
  42.         // Validate init data.8 g- Z# a. B; D/ V( Z
  43.         validate(authData, token, {. p  ~- X# r: q" C5 F
  44.           // We consider init data sign valid for 1 hour from their creation moment.
    ; Q3 {: q( Q) p+ {
  45.           expiresIn: 3600,# B4 N0 R: j: Q4 D/ ~1 e! T- p$ v
  46.         });% T8 j# ~; b+ {0 f/ k; p. e) ?

  47. . t4 l& n3 V0 y" U+ h  W1 @
  48.         // Parse init data. We will surely need it in the future.
    : o( j. \# Y* [' V( L+ ]
  49.         setInitData(res, parse(authData));
    # _1 ~; \/ I* n1 p
  50.         return next();
    6 I+ k+ ^# O. I, N; N* ]! b. @0 Y& X
  51.       } catch (e) {7 E1 D, ^( }* `
  52.         return next(e);
    + y) l( r: z% b
  53.       }
    # D4 Y9 {0 v& P8 _! K5 L
  54.     // ... other authorization methods.
    : V5 G5 B7 ]- q' X
  55.     default:
    1 l& g# n9 D0 k; J( E- Y! B8 T
  56.       return next(new Error('Unauthorized'));
    ! y1 p1 y+ `& j9 q5 g" C# G# Q
  57.   }! N( e6 w, p8 U  f- f
  58. };5 {; Q( U6 w. V

  59. % `$ K$ x) _' H& m# A) D
  60. /**: [/ T- U$ W. T
  61. * Middleware which shows the user init data.# x# t2 B, A. f) z% K9 _* O8 d
  62. * @param _req
    : R0 r3 U6 ~, l" a1 _
  63. * @param res - Response object.
    4 T# t) J0 W. _2 m4 }, `
  64. * @param next - function to call the next middleware.
    / F2 e1 v5 K; o( j1 b) \
  65. */
    . Y& G' ^& [' x1 R: x( o& }
  66. const showInitDataMiddleware: RequestHandler = (_req, res, next) => {( _3 o0 E( Q1 E* D) `
  67.   const initData = getInitData(res);: o+ p0 _- m( O* |0 G: }; U0 J
  68.   if (!initData) {! l& o1 o. X9 Z' U% _1 E" k3 R) S( T3 K* L
  69.     return next(new Error('Cant display init data as long as it was not found'));( `, f0 I5 z4 l5 S+ v5 f2 C
  70.   }
    : f2 ^! @! c6 [3 g( J
  71.   res.json(initData);8 ^6 P! M9 ~4 k0 {' b  ~
  72. };
    - d/ Y5 ]" e* g; H2 `* r

  73. $ c" w/ l( A' j. u$ a8 j
  74. /**
    7 w# G4 O/ L) }- l1 T6 ~! ^! Y
  75. * Middleware which displays the user init data.  ^" k: ]  U  L. A& l. G: A
  76. * @param err - handled error.. K' R8 ]$ e% {5 c
  77. * @param _req6 V' V. h: Z) _2 |" c2 t5 i2 h
  78. * @param res - Response object.
    8 R. ~- g. l) c. E7 L, X3 I$ p8 o
  79. */
    & _0 \  X2 o+ S$ V; U
  80. const defaultErrorMiddleware: ErrorRequestHandler = (err, _req, res) => {
    $ Q0 R5 v0 d2 V4 q3 U
  81.   res.status(500).json({# e* G3 p, U1 ]0 j  d4 n
  82.     error: err.message,; R2 {- a1 o% ?" O* S! J0 e: d/ O
  83.   });7 x4 R$ K2 n0 Q8 w
  84. };; n0 e% K* m8 ~* Y/ W& _1 I
  85. * J/ Y0 u* c. U7 x1 S; P" R
  86. // Your secret bot token./ @, [' ?" m3 }5 i1 b$ m
  87. const token = '1234567890:ABC';
    , e3 X9 ?  g& Y! M) L

  88. , B  S) [, B0 M, K
  89. // Create an Express applet and start listening to port 3000.& O# @& I& @7 d& A2 }
  90. const app = express();
    & ^8 ]3 s9 ]& S0 R

  91. & g+ V8 t9 b6 f% D7 v- t9 G0 j8 p
  92. app.use(authMiddleware);( [- l; R/ {7 {/ M9 t* c
  93. app.get('/', showInitDataMiddleware);5 Q; M( ]+ t6 x8 o  }) j7 C% G
  94. app.use(defaultErrorMiddleware);! M6 q* N, h7 z  P8 _/ {3 N7 q) c

  95. / M6 d( L) O0 v" Q9 ]3 E
  96. app.listen(3000);6 u# e8 T5 J4 }1 G! P9 m

  97. - }+ [9 i8 F1 I2 X3 ~' k8 {
  98. // After the HTTP server was launched, try sending an HTTP GET request to the URL . N. B, A9 x- Y0 o; s! m
  99. // http://localhost:3000/ with an Authorization header containing data in the required format.
复制代码

  A+ R) s8 I$ ~4 n- K- BGoLang[color=var(--vp-c-brand-1)]

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

  1. package main
    7 B. u, G/ m& z) s4 H. u8 g
  2. * U3 O; d$ N: f" B( B3 ~
  3. import (* m+ f4 c, ^# ?5 s3 M
  4.         "context"0 r& o- x# z( Y, O6 Y% ?& c4 n
  5.         "strings"& h0 ^5 D' f  s
  6.         "time"4 I2 O2 h" J' H6 R& d5 E8 d3 b, ?. W
  7. $ M6 ^8 @+ Y! n5 O
  8.         "github.com/gin-gonic/gin"
    ' o; D  ?% k5 @# w; J$ S- P, c
  9.         initdata "github.com/telegram-mini-apps/init-data-golang"
    ( e0 ?' K: O1 U  h
  10. )
    ; |* G1 C8 {0 J3 a  O1 M4 ?) t

  11. & S* ~7 m% x  u1 P8 A
  12. type contextKey string
      H' y9 N) A8 n

  13. 5 v* }- S$ O% d9 N( j$ i; A* O7 P
  14. const () ]9 v, O; Y+ A) T( f
  15.         _initDataKey contextKey = "init-data"
    0 `) }, X' `4 S
  16. )5 Q: ~; C0 D, Y! D1 x

  17. 1 N6 o% o! c+ i, j9 g
  18. // Returns new context with specified init data.
    ) c* `; V4 r8 h2 K
  19. func withInitData(ctx context.Context, initData initdata.InitData) context.Context {
    # D$ Q4 c* \, D5 |/ H
  20.         return context.WithValue(ctx, _initDataKey, initData)
    $ Z# Z9 Q3 {# P$ m2 `* l6 L0 O0 f  c
  21. }
    ; M) l5 r* x# h& q" \
  22. . i* m3 |7 A# v7 }; C5 Y
  23. // Returns the init data from the specified context.% A* }6 Q. b0 D% l
  24. func ctxInitData(ctx context.Context) (initdata.InitData, bool) {
    . J: s1 E3 A2 W2 h* _# o
  25.         initData, ok := ctx.Value(_initDataKey).(initdata.InitData)! m4 ?8 Z$ t- q! f& n* k+ K. A
  26.         return initData, ok
    * u- q. U! @  g9 }. v1 D* k/ W4 B
  27. }
    / B5 R6 Y0 `' q# X9 N
  28. 3 T" L& _) i6 x" X
  29. // Middleware which authorizes the external client." r- E* @+ V" U1 n0 l
  30. func authMiddleware(token string) gin.HandlerFunc {
    7 }( `7 `6 l5 r$ \
  31.         return func(context *gin.Context) {$ r6 y3 n- U; I8 j! c
  32.                 // We expect passing init data in the Authorization header in the following format:
    ! }" e& L4 R: x9 Y. K$ f; J6 U+ o
  33.                 // <auth-type> <auth-data>
    ! b; j5 R3 F& W2 p$ a
  34.                 // <auth-type> must be "tma", and <auth-data> is Telegram Mini Apps init data.
    , l$ m+ |; p8 A9 K* Z
  35.                 authParts := strings.Split(context.GetHeader("authorization"), " ")( Y: K& x5 E. M3 D$ R
  36.                 if len(authParts) != 2 {
    ' G- D$ p' z! W' T" y' @
  37.                         context.AbortWithStatusJSON(401, map[string]any{
    $ E/ b/ N' A; `2 @' ]
  38.                                 "message": "Unauthorized",
      ~" C# \$ l. Z' A8 u/ }- ~) n3 s
  39.                         })
    ) M, p# Y0 e0 ]) I& B1 @9 L
  40.                         return/ s% Q$ x0 t+ t) S1 ]2 _
  41.                 }
    2 t5 Y% A7 z# A/ d  h. J; @' K

  42. * X3 d! m; W/ e
  43.                 authType := authParts[0]7 j3 _5 A1 ?- w
  44.                 authData := authParts[1]# p2 D. l8 q$ S  r& o7 A

  45. ; S6 n% |9 x# ?& h( X) u
  46.                 switch authType {7 f% n% k  h, |; u
  47.                 case "tma":
    & V+ a& ^! q$ V. [4 E5 ^
  48.                         // Validate init data. We consider init data sign valid for 1 hour from their
    4 v" y- t& f. L$ [
  49.                         // creation moment." G; {! W4 x: C0 h
  50.                         if err := initdata.Validate(authData, token, time.Hour); err != nil {
    & @, S0 [8 ~5 T, D
  51.                                 context.AbortWithStatusJSON(401, map[string]any{! O1 p1 X4 v& Q: v, f, K* |
  52.                                         "message": err.Error(),+ U  i( P8 n8 c$ G
  53.                                 })4 O9 ^/ f8 z: {7 D
  54.                                 return
    0 e" n) V$ B" r. \; j% h/ n9 H2 Q
  55.                         }2 |! ]6 ^8 k# W# X9 ]- k9 J

  56. # C/ J' A& p) W" z+ {2 E% W  |
  57.                         // Parse init data. We will surely need it in the future.
    ( R" T0 o$ M# O0 T  y& \
  58.                         initData, err := initdata.Parse(authData)7 [2 x4 A" P1 W# v9 M
  59.                         if err != nil {
    ! S- N  x1 u" ?
  60.                                 context.AbortWithStatusJSON(500, map[string]any{6 j7 ^9 U1 P! r' z: _- z; v
  61.                                         "message": err.Error(),
    $ u( w, y: n( l2 r4 N6 w, ^2 \9 Q0 s8 B  T
  62.                                 })3 y7 F7 ~+ K: M  D, Q, Y- w) E
  63.                                 return! F$ K6 {3 r$ ?1 Z
  64.                         }
    / ~" a3 `7 u. F  l% ~% b
  65. 0 Y1 F' x. e' _9 M; p) H5 S
  66.                         context.Request = context.Request.WithContext(; Q  m$ |2 G! R, u
  67.                                 withInitData(context.Request.Context(), initData),- D4 i4 m' C7 T) _5 O) o7 k
  68.                         )5 s8 s1 q. R6 r$ i3 V  A' X, {
  69.                 }
    6 _6 z* \% m6 y: C# Q* C
  70.         }: y( B" ]: E" |1 u8 t+ j" M
  71. }7 J3 A2 @$ i) v7 H3 f$ Y) R6 T

  72. ) z! P1 x' ]+ ~7 e
  73. // Middleware which shows the user init data.- M/ {9 c- L3 G' C: N6 B# e. L. o
  74. func showInitDataMiddleware(context *gin.Context) {) d, W2 p5 e# }4 X
  75.         initData, ok := ctxInitData(context.Request.Context())' s9 ]+ n! A3 i4 [% V
  76.         if !ok {' w/ h$ y7 X6 k0 R
  77.                 context.AbortWithStatusJSON(401, map[string]any{
    " A: ~: J3 m' i8 W; ]
  78.                         "message": "Init data not found",, d2 d* g: c# M
  79.                 })
    4 x2 o% A+ |! m( W
  80.                 return
    1 d8 {* c( N$ I
  81.         }
    - J! J9 V% ~$ M5 L) l

  82. ' {& e! n2 T  n* {
  83.         context.JSON(200, initData)$ T/ X  h0 C9 N
  84. }' J# Q! C% J$ M, b+ |

  85. - H' X) M3 H- R" p: H
  86. func main() {
    - R5 ~" {, W- ^* b: R0 U
  87.         // Your secret bot token.5 b: Z$ F: R# U2 s+ h5 H; E
  88.         token := "1234567890:ABC"
    & ^6 ?" ^6 q# ^' I! b8 H2 s9 c, A3 z

  89. # }  x0 A4 x+ B$ U3 d) w
  90.         r := gin.New()
    : a. _9 [4 H& }" l5 o$ ?

  91. $ c7 r8 O) U5 T5 C
  92.         r.Use(authMiddleware(token))
    / a6 @! T0 ]$ g5 T9 E# L: P1 F
  93.         r.GET("/", showInitDataMiddleware)1 S: }# `5 x7 J& O7 ?4 g3 W
  94. $ @& x1 }# C$ Y. A+ c
  95.         if err := r.Run(":3000"); err != nil {
    ' D( o) T6 A4 p- i- l: j8 ]3 l
  96.                 panic(err)0 A4 b/ y* l; I* G9 w
  97.         }# H6 y8 v0 e5 G: P( R3 ?
  98. }
复制代码
7 t7 S6 r- k) H+ S
7 k; Y; s! B8 |8 r( k
分享到:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则