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

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

回答

收藏

Telegram小程序 指南 | 授权用户

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

本帖最后由 riyad 于 2025-2-21 19:27 编辑
/ C& Q! G$ x  ^+ J3 b9 J0 _
8 ]/ _1 y6 E0 u3 F. g

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

0 ]) P: M$ N0 v$ l5 ?% s
客户端

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

  1. import { retrieveLaunchParams } from '@telegram-apps/sdk';8 _& d# ~( q5 T% f

  2. 5 h' \" v5 x  L3 j
  3. const { initDataRaw } = retrieveLaunchParams();
    & \7 F5 C' m7 D4 G3 D

  4. 7 [/ ]1 e) z# F% e! a7 L
  5. fetch('https://example.com/api', {
    ' B7 E4 k7 g/ d0 w' }( b  U7 O8 w" e" B
  6.   method: 'POST',
    " [2 |5 z& q5 N$ y( X
  7.   headers: {
    ( e2 A+ ]% t: D* f0 g6 Z
  8.     Authorization: `tma ${initDataRaw}`$ n' U# ?1 p" B6 g+ [
  9.   },
    + t/ S; [/ K8 C" t9 N$ g) P
  10. });
复制代码

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

2 c1 ~! \- O* Z8 ?
服务器端

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

Node.js

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

  1. import { validate, parse, type InitDataParsed } from '@telegram-apps/init-data-node';
    $ @2 T# i  [" C/ D# O
  2. import express, {/ j" R' R& ~0 {- A# B) ]' i
  3.   type ErrorRequestHandler,9 d5 Q+ @/ I5 d% X6 \
  4.   type RequestHandler,
    & G. p3 C- e8 i0 w1 E
  5.   type Response,$ W% _7 N. d! X5 P/ z# `' @
  6. } from 'express';  P; G) s% T5 e% V* p
  7. / \& e/ u& H( e. v+ b
  8. /**
    $ z$ n: r; _$ o+ c. [' f7 U
  9. * Sets init data in the specified Response object.0 E* {- V: w" d: s9 M
  10. * @param res - Response object.
    6 x# ~) g) V$ ^; h
  11. * @param initData - init data.6 U( A; T1 I; z* f( t) M
  12. */* v0 c0 i! y% q7 t
  13. function setInitData(res: Response, initData: InitDataParsed): void {
    " ~6 E2 {5 g7 g6 l9 l" N
  14.   res.locals.initData = initData;
    1 ~- n7 Y* ?- m4 U3 z1 j* q2 _
  15. }, n1 r$ m6 x1 \7 w) a
  16. 4 _# N0 i6 M% v0 S
  17. /**
    / h/ h% r4 E4 h% W
  18. * Extracts init data from the Response object.
    ' Q4 Y0 y& S. o: I: |- L6 E/ f
  19. * @param res - Response object.+ Z7 e$ J/ V4 b9 n2 {) |
  20. * @returns Init data stored in the Response object. Can return undefined in case,
    : l! a, D( S9 m$ R& }5 K1 I
  21. * the client is not authorized.
    ( |9 V) d# V  `
  22. */
    ) U; j" a1 N. m9 P, D4 C5 x4 |9 g( X
  23. function getInitData(res: Response): InitDataParsed | undefined {* K3 N4 ~  |3 A: n# e
  24.   return res.locals.initData;
    + Y8 q2 ~$ h+ I5 p6 |- m
  25. }
    " E5 W4 V* R$ G' G0 @$ w0 N: p

  26. $ G6 h! o) t, ~4 m
  27. /**6 Z2 G2 s5 a9 a9 F
  28. * Middleware which authorizes the external client.7 n+ U0 q" x7 z3 q1 b
  29. * @param req - Request object.
    1 l2 \" f# u* E- H% u7 [
  30. * @param res - Response object.! `. ^- D' J# x* T1 ]; q
  31. * @param next - function to call the next middleware.
    4 K; Q/ w7 }% _7 x; y0 g6 N$ [
  32. */; S- V$ V9 A! E
  33. const authMiddleware: RequestHandler = (req, res, next) => {
    ; o: L6 }* F+ C' F, \
  34.   // We expect passing init data in the Authorization header in the following format:; x7 ~; s" N# n. H5 T% t9 n
  35.   // <auth-type> <auth-data>1 f, b% p5 Z. u3 ]2 v
  36.   // <auth-type> must be "tma", and <auth-data> is Telegram Mini Apps init data.
    - i% t# K: W) {* q/ y$ E
  37.   const [authType, authData = ''] = (req.header('authorization') || '').split(' ');
    5 \5 s) c8 M" a2 \6 k; F3 e
  38. ( B6 N" A$ z2 o  J2 ?$ [
  39.   switch (authType) {6 x5 k* x% Z1 _* `% c& a
  40.     case 'tma':. T5 E+ R/ X! t# d* x
  41.       try {
    4 r6 P; u0 G" D  q
  42.         // Validate init data.
    , T$ c* u! N5 b' Z" i) K; m- ]
  43.         validate(authData, token, {
    * h2 ~* V1 X. a1 ^, L- m' J8 Y
  44.           // We consider init data sign valid for 1 hour from their creation moment.( J$ o# c! d% N& Y4 ?
  45.           expiresIn: 3600,) a$ t+ j8 r$ q4 L. z6 K& E. V
  46.         });
    0 R- W9 T8 W; m$ r, v6 V& R0 Q
  47. / Y; d+ i) e! z. Y1 p5 A1 y
  48.         // Parse init data. We will surely need it in the future.; Y2 a7 K- @( u2 w/ N4 @
  49.         setInitData(res, parse(authData));
    1 Q1 C/ S5 y! S& J. k1 c9 M
  50.         return next();
    ' {: S# Y; ?4 V5 f0 F- M) r! e" W
  51.       } catch (e) {
    ) ^% @  R; R9 K2 O# |
  52.         return next(e);
    ( k& l$ }/ n+ o; F) g
  53.       }3 M! M6 \/ m, U, `! H( _
  54.     // ... other authorization methods.
    6 k; |* L: o" h. J: F
  55.     default:. P/ S! U9 H0 M0 M
  56.       return next(new Error('Unauthorized'));! C1 @- c) C, ]& u- L
  57.   }
    2 }4 [# W+ Z# H: y
  58. };! f( i1 @+ @+ r5 h5 a" S% [* P

  59. 7 ?5 r* O* N; d$ u5 O& n! B1 K
  60. /**: v# y$ o- g  z3 H
  61. * Middleware which shows the user init data.$ c* v" |( A% ~* C% j
  62. * @param _req
    * V- c/ a4 o1 S# c
  63. * @param res - Response object.4 {6 C8 u) o% j& t5 G( Q
  64. * @param next - function to call the next middleware.4 d, P$ Q) n* {2 L9 a: [! x, W6 ^# {
  65. */
    : i- k3 C" o$ k' `% B
  66. const showInitDataMiddleware: RequestHandler = (_req, res, next) => {! \& a1 f8 T  D+ }0 m! R9 |
  67.   const initData = getInitData(res);
    ' x7 i4 l8 g6 S" ]
  68.   if (!initData) {
    1 U, z2 G* p" p# R$ ]: w
  69.     return next(new Error('Cant display init data as long as it was not found'));
      T1 |( ]# U# r5 c6 @. I4 V6 O6 |
  70.   }
    ; ]5 a. i6 S* N+ D- i
  71.   res.json(initData);: \6 C+ n& P' J# r' @+ D/ k
  72. };9 }  \- ?+ C6 Z1 Q1 L
  73. # n0 W9 {' \" |* u0 V( u3 a5 y
  74. /**
      |1 t9 U5 K, u) N0 D3 g
  75. * Middleware which displays the user init data.
    2 y% N; {, i% S
  76. * @param err - handled error.: N9 d" ^) y  \7 ?0 H
  77. * @param _req' ?2 w) k) J5 S) D1 E1 Q
  78. * @param res - Response object.6 u: J8 Q7 ]1 O5 ~4 J! ?
  79. */
    2 G; ]) d' P7 l1 a3 I
  80. const defaultErrorMiddleware: ErrorRequestHandler = (err, _req, res) => {
    : T; Y( C8 a8 @6 A
  81.   res.status(500).json({' `9 X) ~) I3 F+ o8 x, n
  82.     error: err.message,6 e) M, }! U- Q
  83.   });
    - i5 ^% D/ M2 Q
  84. };
    9 I. q/ {+ M* M% [& V8 h" W
  85. ' I/ U* v% q/ a1 O* c% ~% }/ N
  86. // Your secret bot token.
    2 v8 C0 [7 ~1 F, j9 x/ u& Z3 R
  87. const token = '1234567890:ABC';
    ( ^, L) Q$ r: M8 W4 Q9 p

  88. ( ^3 [0 O  D% X' ]6 g  V; X
  89. // Create an Express applet and start listening to port 3000.
    ( V& c% \' X# S! f1 H7 h; ~
  90. const app = express();! s% O' v, r1 m- \( d
  91. ! o" Y& {3 G# r* P" u
  92. app.use(authMiddleware);
    . J' i* D$ q# I6 Y
  93. app.get('/', showInitDataMiddleware);. o3 k$ |& R* ~# J+ O
  94. app.use(defaultErrorMiddleware);: ~0 z9 A7 W# D- u/ H! s' c

  95. ' B; T& A8 X% E2 e# Z" q+ C
  96. app.listen(3000);- y  \+ `) R7 F& s* S1 l
  97. * ?- X5 z. G* `9 Y; |# M( j
  98. // After the HTTP server was launched, try sending an HTTP GET request to the URL : W9 q* C! J+ N1 ^
  99. // http://localhost:3000/ with an Authorization header containing data in the required format.
复制代码
8 o8 n# X. u, Q  s$ _
GoLang[color=var(--vp-c-brand-1)]

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

  1. package main) N% v  t; L2 x

  2. ; G  i* N9 N. f& p+ j0 J
  3. import (
    7 t. x2 i6 S1 Z: I6 ^
  4.         "context"
    0 x- }" I& }4 w7 ^
  5.         "strings"+ v0 E2 b2 k) s/ x. {
  6.         "time"
    2 o6 y  t  q& c8 A+ k
  7. , ]& S0 p  q9 h: P! F5 `4 A
  8.         "github.com/gin-gonic/gin", F' E9 {( R; R, K* O  d) _# d" \
  9.         initdata "github.com/telegram-mini-apps/init-data-golang"( S1 V; [3 E0 {1 L9 s+ g& Z
  10. )
    8 N7 G+ @% T! R  p( s

  11. 6 `% u" x2 c4 h' _
  12. type contextKey string
    9 H3 Y+ |# f$ T; h$ q* Q* i$ m- D

  13. & x# V0 L* H3 D3 L/ x  K
  14. const (0 l  ]4 N0 M2 P  s. z3 m
  15.         _initDataKey contextKey = "init-data"2 R0 e' r5 h  v& v
  16. )
    ( z9 M0 ^5 X& F/ _

  17. 0 t1 h  g/ M$ F" v! p) l3 A( h
  18. // Returns new context with specified init data.2 b8 Y' S  n3 H3 a  X5 i
  19. func withInitData(ctx context.Context, initData initdata.InitData) context.Context {
    7 ~% z4 ?! I4 ]% I9 J
  20.         return context.WithValue(ctx, _initDataKey, initData): G7 l  G* p* N! j5 h* c
  21. }( _  P5 H( j6 `2 q* I, ]

  22. 6 ~, K% t6 \; d- A# A7 n; T
  23. // Returns the init data from the specified context.* F) ^9 a! z1 o! {9 Y, m$ _
  24. func ctxInitData(ctx context.Context) (initdata.InitData, bool) {
    ( r: S, K# T) c* R- E" Y; t& k
  25.         initData, ok := ctx.Value(_initDataKey).(initdata.InitData)
    # s  y# c7 }7 @6 U9 o& D4 f% _7 p
  26.         return initData, ok
      k* ?4 h; T1 f' k
  27. }
    6 A& U$ O/ W" d1 B
  28. 1 `) d6 r: B1 ]
  29. // Middleware which authorizes the external client.3 F. I2 u  ]- u3 O4 R- c  K
  30. func authMiddleware(token string) gin.HandlerFunc {+ m2 k' J+ Y& N* |
  31.         return func(context *gin.Context) {
    . P8 j9 t$ u4 u0 ^! V
  32.                 // We expect passing init data in the Authorization header in the following format:, ~3 f$ p, t9 P5 G: j( A
  33.                 // <auth-type> <auth-data>
    % ^* _% ^3 @( K7 l; `
  34.                 // <auth-type> must be "tma", and <auth-data> is Telegram Mini Apps init data.3 _( X. o! A2 M: y5 ~2 k# o/ |
  35.                 authParts := strings.Split(context.GetHeader("authorization"), " ")
    2 u& b& d3 i# Y4 P; o8 z
  36.                 if len(authParts) != 2 {
    " a: Z# p0 I$ {* x& E* M8 k
  37.                         context.AbortWithStatusJSON(401, map[string]any{
    4 ]- J4 u$ U0 v& a; W
  38.                                 "message": "Unauthorized",& B* P& O/ ?6 a7 s* e. s1 h. o
  39.                         })
      F/ Q: J! Y* G( Z4 g9 M* a5 x
  40.                         return. b" i) j  I9 D& J8 X8 e& j, R, ^
  41.                 }
    5 g- o$ l% {' a9 o4 ^( o9 W
  42. 4 [4 z. k8 W' c! M7 s9 h
  43.                 authType := authParts[0]
    % Q9 _+ j1 M0 `( K2 v, T
  44.                 authData := authParts[1]* Q6 b$ k; \. r9 b
  45. + r7 e7 X' K! S4 L$ d' K" J
  46.                 switch authType {% n9 {: t7 T; X4 t1 T. T
  47.                 case "tma":) M( @5 n& i( j" j8 [$ r4 r  E, K
  48.                         // Validate init data. We consider init data sign valid for 1 hour from their
    0 n$ x0 \. l3 f6 U; V
  49.                         // creation moment.
    3 _3 c4 L5 ?+ M: N' y
  50.                         if err := initdata.Validate(authData, token, time.Hour); err != nil {' f7 ^7 t, _! T. b) r% \4 T
  51.                                 context.AbortWithStatusJSON(401, map[string]any{& \1 `6 x7 l1 ]6 J3 c
  52.                                         "message": err.Error(),
    * l- A- R* A) k9 [3 ]5 \
  53.                                 })+ E" O$ l' E! X, x) t
  54.                                 return7 y- F! _1 w; U. l- v3 l
  55.                         }- y. `6 }2 \( k5 s
  56. % g8 L4 f& H# G; H
  57.                         // Parse init data. We will surely need it in the future.
    % O8 A8 s7 {, q# B/ ?4 Z
  58.                         initData, err := initdata.Parse(authData)
    & \6 E2 u2 q) E! V/ A% W1 }
  59.                         if err != nil {
    7 {$ M& V* e, o2 Y1 J
  60.                                 context.AbortWithStatusJSON(500, map[string]any{; A5 J4 a8 q( Z. C, \
  61.                                         "message": err.Error(),1 S; w# }9 c+ i
  62.                                 })
    1 n3 C- S2 C+ A$ m3 [3 n1 H
  63.                                 return
    , h) z6 S/ V( X9 b3 R8 O8 `1 O
  64.                         }
    % E, _; q7 c* T+ D  n

  65. 4 v( v- c& q0 K/ b5 ~  x2 r, k
  66.                         context.Request = context.Request.WithContext(
    ' {9 p! \: A9 R! T% U
  67.                                 withInitData(context.Request.Context(), initData),8 D* F. {% Y3 y
  68.                         )
    + `8 W9 U' h# S5 ~4 a) Y+ A! [
  69.                 }( D' O0 p+ l, I+ C: A
  70.         }
    ' t2 m) Y) q: I: u* w5 s
  71. }' G& a& t, L7 W( ]; ?3 @4 R

  72. ( `4 l# P# Y. B+ I5 X0 W+ U6 A4 ]
  73. // Middleware which shows the user init data.
    3 U  Z! y0 y# f1 `. F# S6 T& J/ K
  74. func showInitDataMiddleware(context *gin.Context) {
    , D0 V+ M1 m2 I; }9 G
  75.         initData, ok := ctxInitData(context.Request.Context())
    . h, }- h- @4 b' O8 J1 S$ n
  76.         if !ok {2 S6 M& _" Z6 ~2 P/ G2 F4 F
  77.                 context.AbortWithStatusJSON(401, map[string]any{
    3 r: j9 E+ V5 F9 p1 P% T2 X
  78.                         "message": "Init data not found",
    # \* ~( ~, x$ Y4 P/ ?. q
  79.                 })
    + k: L$ P2 y/ X. y7 W' A% B) S' l
  80.                 return, U6 V9 H8 |, l& @6 f9 _2 O
  81.         }
    ! H$ X8 z% p6 @3 Z$ d% T
  82. " s2 N( y6 t# g0 J3 y8 T0 f
  83.         context.JSON(200, initData)3 B- k$ m+ ?9 m& L; d3 p
  84. }* J7 B- e$ ?" |% z& q

  85. 0 E3 ?1 t. j- D1 v+ w
  86. func main() {- X' Y: J6 U- v* ^9 H6 o
  87.         // Your secret bot token.& Q( q3 F! d" n1 r9 K" u
  88.         token := "1234567890:ABC"
    9 e! h6 n: ?# j5 Z9 n" p; P
  89. + S" d, {+ u" I& D
  90.         r := gin.New()
    + H0 f. z4 w2 D: C/ ]1 Y! o
  91. # g( v/ v- R5 B0 e8 `* S- Z
  92.         r.Use(authMiddleware(token))* v. W# y/ G) |1 T, Q) ^1 M
  93.         r.GET("/", showInitDataMiddleware)' o! ~6 K( m; v

  94. ! @! g7 R. n& _. D4 X$ V# ]
  95.         if err := r.Run(":3000"); err != nil {7 |7 y* A8 }) F% V" e! y( U
  96.                 panic(err)5 B5 g7 ~8 B# T2 W: ?
  97.         }1 K! C( ?' H' ?  i& U
  98. }
复制代码
- V6 n# t+ {7 J, j" f9 f; S
7 {6 t* N1 m; s" A9 F# l
分享到:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则