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

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

回答

收藏

Telegram小程序 指南 | 授权用户

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

本帖最后由 riyad 于 2025-2-21 19:27 编辑
2 l4 ]3 [2 L6 P# k
- i. v( n  Y- w3 U7 B

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


  v6 R" w% I3 u: }客户端

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

  1. import { retrieveLaunchParams } from '@telegram-apps/sdk';1 m5 p" e) y7 U" A4 K/ j

  2. " h: V9 v' i9 p: i4 ?6 J
  3. const { initDataRaw } = retrieveLaunchParams();
    " O: }: I7 I7 m: I% [; r
  4. 5 ^+ S# J+ ~- d: x. F
  5. fetch('https://example.com/api', {* ~) t- b, Y: w
  6.   method: 'POST',4 z7 K* G' T: I; n
  7.   headers: {3 y4 R- w  x4 p  P
  8.     Authorization: `tma ${initDataRaw}`
    : @% A9 ^2 d( ?% i$ }# P
  9.   },  P5 u3 C9 i7 U9 e: z- r) U( ?; J; i9 e
  10. });
复制代码

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

" K3 d& X- h8 d/ T# e% L1 m
服务器端

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

Node.js

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

  1. import { validate, parse, type InitDataParsed } from '@telegram-apps/init-data-node';: U" E) k4 [  W% ?, W
  2. import express, {
    6 V7 Q# g3 a5 U+ h. T- ^
  3.   type ErrorRequestHandler,& X' Y& _9 b3 R, [) {. C) Q
  4.   type RequestHandler,0 i6 t1 ?* E& `  l, X
  5.   type Response,! G9 `( _# \7 m+ S% e
  6. } from 'express';; X+ x/ V% c* i% |3 P% m, a

  7. ) b) L/ w, A4 W3 u- l
  8. /**7 n  j7 O9 z( N; P( n
  9. * Sets init data in the specified Response object.
    $ p* c- L' s$ ?# r* u
  10. * @param res - Response object.- |1 n0 v0 w3 y6 H
  11. * @param initData - init data.
    # Y% [2 f* g# u4 t
  12. */
    8 N, G% Q& R" `7 H
  13. function setInitData(res: Response, initData: InitDataParsed): void {
    : ?8 |1 e" ~/ U. s, |' [) D
  14.   res.locals.initData = initData;
    5 x+ ?& m/ Y8 t
  15. }( M1 \2 d& L$ D5 C  X7 v

  16.   A/ G: t# a4 d$ ~
  17. /**2 W$ A* S# n* Z9 K, x3 l
  18. * Extracts init data from the Response object.
    & t) _1 j  a& x/ p0 ?# _& E, ~
  19. * @param res - Response object.* A- w' m- B6 B, M/ v
  20. * @returns Init data stored in the Response object. Can return undefined in case,  W# S7 A' t3 T: O
  21. * the client is not authorized.( Q" U' A/ s3 g6 t  b9 q- b
  22. */
    ( Y$ b9 ]/ z  k: x, o
  23. function getInitData(res: Response): InitDataParsed | undefined {
    4 I0 g. x, ]% _) D* T
  24.   return res.locals.initData;
    2 X% O; F6 @0 D) u1 H
  25. }$ p& _) U$ M' r+ [; K. r

  26. / E  N: @4 _) W* [4 N  P2 s% p
  27. /**( I7 L* c' J# l  @# I5 r+ \
  28. * Middleware which authorizes the external client.3 T4 ]" G1 a' o. X: K" m* F+ n+ v
  29. * @param req - Request object.
    9 i" b' u0 g- l2 B  ]
  30. * @param res - Response object.
    0 a8 i+ J/ R7 V$ g6 f+ s+ D2 z
  31. * @param next - function to call the next middleware.
    - t! c( F0 X8 O# a& c3 }
  32. */( r4 P1 H1 U/ `9 Y9 B/ m: }
  33. const authMiddleware: RequestHandler = (req, res, next) => {! q5 A$ F  i9 |6 C  J
  34.   // We expect passing init data in the Authorization header in the following format:. {8 L& t2 `0 X% r
  35.   // <auth-type> <auth-data>- R) z- q" Z2 L- D' c/ p
  36.   // <auth-type> must be "tma", and <auth-data> is Telegram Mini Apps init data.' O- X1 s$ H( H
  37.   const [authType, authData = ''] = (req.header('authorization') || '').split(' ');
    , w. z3 Y- M# w$ C

  38. 4 F" T& T0 n# J6 A+ N  u3 A
  39.   switch (authType) {1 T2 g8 E$ r; N; F- r
  40.     case 'tma':6 N' r- B. a3 @4 i
  41.       try {, c2 q8 @8 Y8 j0 r: Y& X
  42.         // Validate init data.# N0 X( B" R2 j$ a: r& j
  43.         validate(authData, token, {
    ! ]7 n4 a) f9 Q
  44.           // We consider init data sign valid for 1 hour from their creation moment.) Z/ Q3 w: M( Z* j0 y$ g* g
  45.           expiresIn: 3600,- K) ]+ G0 G* H0 H& F& p
  46.         });) o2 g; ?  n1 d' c" o
  47. , ?) `8 M7 a5 _9 X
  48.         // Parse init data. We will surely need it in the future.
    7 V1 u2 a4 X2 i) u% p
  49.         setInitData(res, parse(authData));
    * D/ `5 o. U9 A
  50.         return next();
    * B" h6 R- U7 v6 F/ R7 z
  51.       } catch (e) {
    " x  G  z% }- T8 q0 K3 b4 y: I1 ~  [2 y9 k
  52.         return next(e);
    0 G4 G3 M% P" d5 h1 s6 g$ B
  53.       }
    & k6 y. B" [* V& T' o4 i: }
  54.     // ... other authorization methods.1 ?3 c" B1 K) A9 A, z, p
  55.     default:8 j1 h% Q* a" @; l( K% Z: l
  56.       return next(new Error('Unauthorized'));8 b& `- B9 x. O. f9 E: r9 y
  57.   }
    " w1 @7 f7 x& G" I
  58. };. D; t* n, [/ R! n* d! D

  59. ( s8 m5 b+ L) ~2 m+ h) J, l  y
  60. /**0 e4 l1 t6 I" J1 _* A
  61. * Middleware which shows the user init data.+ B: a$ ^' v' k, J9 M
  62. * @param _req
    2 ?1 i2 k2 N& Q! P
  63. * @param res - Response object.; F  h5 _5 ?$ K" J. i; {* r
  64. * @param next - function to call the next middleware.+ p0 h) x  }/ p2 O- T
  65. */, P5 ~' o& U9 _5 t9 l' e  _
  66. const showInitDataMiddleware: RequestHandler = (_req, res, next) => {6 [( @) A" T/ F+ V. {3 ^' D1 s
  67.   const initData = getInitData(res);0 x8 N3 ~- P+ P1 H
  68.   if (!initData) {9 C, p8 ?+ U9 b$ S8 v; L
  69.     return next(new Error('Cant display init data as long as it was not found'));
    + U2 A1 ]4 v! ~! U( o
  70.   }& Q* L0 H  T- O! F& C( \' E) e
  71.   res.json(initData);
    : l& }+ s! n: ^- N2 X; ~
  72. };6 k' R7 I7 {$ X6 w, M0 ?- x
  73. 8 G7 v: a5 c0 Q7 v
  74. /**5 ?7 t7 d7 C9 j% ~& t
  75. * Middleware which displays the user init data.. c! G1 \/ h# s0 V4 y! a. c2 _
  76. * @param err - handled error.( G" E/ w1 U2 l7 H6 F
  77. * @param _req
    # [; [% M4 X( U  |' E5 ]
  78. * @param res - Response object.
    : K( F1 Z/ x0 Z; J: x3 t2 O& A
  79. */3 v# S) b! ]! M& @- U
  80. const defaultErrorMiddleware: ErrorRequestHandler = (err, _req, res) => {
    ) j6 x1 x8 a0 O2 I4 I1 |1 k
  81.   res.status(500).json({/ e% \# A* n' J" [
  82.     error: err.message,
    " s% y0 W# t$ S/ k4 ~# [$ O. Z5 v
  83.   });
    ! ?% r9 n& u; V, z( J  P
  84. };
    2 U& f; m! h; ]- H( `7 c

  85. ! y5 ?  ?$ m. A: X# k6 c
  86. // Your secret bot token.8 j0 G$ p0 C6 g5 s
  87. const token = '1234567890:ABC';: g5 _/ u4 B3 Y

  88. % F" m2 t& Y- x( T
  89. // Create an Express applet and start listening to port 3000.# u: h& W1 g' W  a& s! Z
  90. const app = express();
    ! A/ B4 F, a, B' D( w/ w

  91. 7 N2 \- C' H% D# }* I. B
  92. app.use(authMiddleware);( ^: E# u! m' }! P4 y
  93. app.get('/', showInitDataMiddleware);
    ( V& D7 U! y1 @  q! W7 k0 @
  94. app.use(defaultErrorMiddleware);
    6 q% w/ d- r, }9 e! f8 [' J

  95. ( u/ P$ V" |% U, p6 H4 t
  96. app.listen(3000);
    $ P3 v$ l2 P9 Q9 n! V
  97. 6 G1 u$ d; f' ~- I; k* S% F3 Z
  98. // After the HTTP server was launched, try sending an HTTP GET request to the URL
    : y6 n/ L7 d4 O1 m/ B2 W3 m! c
  99. // http://localhost:3000/ with an Authorization header containing data in the required format.
复制代码
9 H) D: H1 Z* z5 ^$ \
GoLang[color=var(--vp-c-brand-1)]

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

  1. package main. X" b& `0 `, S- D0 u$ ^
  2.   D) I. R, `* F* h% E# p" F5 U
  3. import (2 T9 Q( n; \$ G3 w
  4.         "context". O( `* H, C  K  w# D, r3 @
  5.         "strings"
    , W( a, ~6 t( J, U* d( V
  6.         "time"
    % [1 ]; |" c3 x& `3 E8 a" Q
  7. % a4 f6 o: Z& V: }+ m( g: Y6 P
  8.         "github.com/gin-gonic/gin"
    + w4 C5 f9 a; u1 _* y! g
  9.         initdata "github.com/telegram-mini-apps/init-data-golang"6 B  ~) Z* ^. J$ h
  10. ), T; n9 s  m. F: a/ D& [

  11. 0 r( a' F, [4 E9 c9 f# B
  12. type contextKey string. B: j- `: Q& J3 V4 F4 s) I

  13. # J, n, q8 [: f) {
  14. const (# j- C' K* p+ q0 u
  15.         _initDataKey contextKey = "init-data"5 m3 {6 D' \! g& [4 m: N: h+ n& @
  16. )0 X' X7 O$ E, s# L% g: E
  17. # T! T8 [6 h8 I1 |8 `
  18. // Returns new context with specified init data.
    , A3 G+ M1 f% c' c4 `
  19. func withInitData(ctx context.Context, initData initdata.InitData) context.Context {) X5 M; a2 f. U% S) Y4 h% x! W& _
  20.         return context.WithValue(ctx, _initDataKey, initData)# h- z/ _9 U' S* ~
  21. }
    3 m5 t( |9 k) S# u& t5 j
  22. * x3 E% p, M8 d$ v) G4 D3 m7 g" M
  23. // Returns the init data from the specified context.: [, O! w0 e( D& m0 N! |
  24. func ctxInitData(ctx context.Context) (initdata.InitData, bool) {9 W3 j1 X* Z! l  G! i
  25.         initData, ok := ctx.Value(_initDataKey).(initdata.InitData)
    ! M! a9 w- l! y' o: g! F* d" ^" k
  26.         return initData, ok
    / v9 ]- E" T5 h& T( S5 O
  27. }
    2 L% D4 e" D7 ]
  28. ! n6 g. B, E4 z+ W! l, W
  29. // Middleware which authorizes the external client.: v' G, I! J/ M$ _6 I* @
  30. func authMiddleware(token string) gin.HandlerFunc {
    " K6 ~9 T7 c! B9 i2 k/ D
  31.         return func(context *gin.Context) {
    1 Q. e8 w2 g3 b! K8 H4 ~, A1 F1 R
  32.                 // We expect passing init data in the Authorization header in the following format:7 L) `' B2 W* W
  33.                 // <auth-type> <auth-data>
    $ s) \  Q6 A8 i
  34.                 // <auth-type> must be "tma", and <auth-data> is Telegram Mini Apps init data./ U' w8 @3 |5 a0 Y+ F5 P
  35.                 authParts := strings.Split(context.GetHeader("authorization"), " ")
    ) v: y: E. y9 O  |/ b! W
  36.                 if len(authParts) != 2 {
    & F* S. U& T! q
  37.                         context.AbortWithStatusJSON(401, map[string]any{$ D  f8 p$ y8 a- h1 N
  38.                                 "message": "Unauthorized",
    ( I' X# X" e8 z5 ^  d4 T- c
  39.                         })
    . W" ?& b, H7 f1 i; `
  40.                         return
    , R) T' d0 m1 w5 L+ E9 F# J+ h
  41.                 }# y6 ^& y" z% x9 R0 u: ^# }  ^
  42. , V# p, R9 ^! @( v" S
  43.                 authType := authParts[0]
    ) B# F# F' \: ^. d: z1 z
  44.                 authData := authParts[1]3 o( I' T  y6 Q" F9 A# h/ |# j9 w
  45. " E6 c& \( r  _8 \
  46.                 switch authType {
    ! ~- d5 {0 X: Z. _# L. M0 i8 x
  47.                 case "tma":
    # D7 t1 C+ b; Y/ Y: `
  48.                         // Validate init data. We consider init data sign valid for 1 hour from their
    & i5 {& {4 p( U
  49.                         // creation moment.
      k, f& H/ m0 Y1 \
  50.                         if err := initdata.Validate(authData, token, time.Hour); err != nil {9 |: H4 L) `: P9 P9 `
  51.                                 context.AbortWithStatusJSON(401, map[string]any{8 u9 Q+ `  {9 Q3 M5 K. z2 w
  52.                                         "message": err.Error(),
    * F1 U  b. ?; c; y# U
  53.                                 })
    ; ?! d& e8 z/ E. [2 r: b+ F
  54.                                 return8 @& ^+ s9 f- o: b1 z
  55.                         }& {! ?# ~9 o' O3 M
  56. : w: m& D6 o& k. _
  57.                         // Parse init data. We will surely need it in the future.) J5 t, O* f' O* R2 I& [  ?: l3 L
  58.                         initData, err := initdata.Parse(authData)
    2 X  b0 E/ o4 @4 L8 n! h' u  }
  59.                         if err != nil {5 A! l. B0 h' L. z& s+ d5 p* g
  60.                                 context.AbortWithStatusJSON(500, map[string]any{
    - c! S/ Y4 X5 w% N- ^
  61.                                         "message": err.Error()," d6 A' R) {; P2 X: b" s# n
  62.                                 })8 T# T4 l  W9 c- l1 }, ^
  63.                                 return
    # b' T# T- I& R% n* j
  64.                         }5 V+ }% u1 e3 t8 Z( d2 u- y

  65. * x% I6 H  c2 B% a3 k
  66.                         context.Request = context.Request.WithContext(
    5 }6 I+ ~6 u2 {! [% w) y6 k
  67.                                 withInitData(context.Request.Context(), initData),0 w7 Y3 I5 e. |5 m6 y! h; i. I( U6 i
  68.                         )7 a* a; o: ]/ ^) R" w
  69.                 }# v* P+ B7 b: j  }
  70.         }0 t' n. b- x. B
  71. }# A* j  a' h$ h5 Q6 }

  72. $ o9 ?7 e  c( ?! V1 ?
  73. // Middleware which shows the user init data.+ P7 }1 U; }3 l( _1 P+ r  v
  74. func showInitDataMiddleware(context *gin.Context) {
    2 R: P: q/ n9 S% l1 J
  75.         initData, ok := ctxInitData(context.Request.Context())
    2 o. c) ]# _( _; k
  76.         if !ok {' Y6 u3 v+ H  P, u1 z! X
  77.                 context.AbortWithStatusJSON(401, map[string]any{
    5 D9 y8 i, z: K; v4 [0 ^. w
  78.                         "message": "Init data not found",
    , B6 b, ~6 J2 @
  79.                 })- _# j8 A! W8 v& |. b2 J
  80.                 return
    ! G. [1 A% I, Y8 p: k! Q1 h
  81.         }9 ?8 i" ~0 R- T+ z
  82. 7 Z# H, @/ n. i6 U0 ^+ ^
  83.         context.JSON(200, initData)
    + O* A. X1 l& Y  w" Z% A6 J
  84. }) C- p3 n" {$ P
  85. + _' t4 F* q4 ^& ]4 c
  86. func main() {9 J8 @" A$ r$ r# I2 A5 p7 m
  87.         // Your secret bot token.
    * C# f) T( W  P& R
  88.         token := "1234567890:ABC"
    0 L" w+ _$ W' l: }7 _
  89. 6 U4 v3 r+ d. l& @
  90.         r := gin.New(); [1 z4 {2 ]! s6 Z# q- k# I

  91. " |! |  E5 b/ |8 D$ }- J0 w0 }
  92.         r.Use(authMiddleware(token)); I4 P* j1 n9 L; S/ m, f" [
  93.         r.GET("/", showInitDataMiddleware); s/ P, e6 T( H- F

  94. 9 G' S- @- g* U2 G4 e  I
  95.         if err := r.Run(":3000"); err != nil {
    # R! h6 Q) y- x3 J$ m
  96.                 panic(err)
      W" X5 Q( W6 E, {
  97.         }
    7 A1 \4 Z' E+ m* p- l
  98. }
复制代码

' r/ L# a4 y; \4 b; ?8 |" l7 b1 G8 \! Q/ k
分享到:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则