Telegram第三方登录步骤

网上看到的不多,简单做个记录,本文主要对下面的文章做补充

Telegram(电报)授权登录(web)第三方

整体步骤为:

  1. 找 botFather 创建机器人
  2. 给机器人设置域名白名单,用于设置回调地址,官方回把用户信息返回此处,所以注意,域名需要能被 tg 官方调用到,像内网、国内 ip 等,是无法回调成功的;而且需要配置 https
  3. 去官方的 https://core.telegram.org/widgets/login#widget-configuration 选择回调方式;回调方式有两种,第一种直接返回前端,第二种接口后端

以第一种为例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
<script async src="https://telegram.org/js/telegram-widget.js?22" data-telegram-login="watchx_test2_bot" data-size="large" data-onauth="onTelegramAuth(user)" data-request-access="write"></script>
<script type="text/javascript">
  function onTelegramAuth(user) {
    alert('Logged in as ' + user.first_name + ' ' + user.last_name + ' (' + user.id + (user.username ? ', @' + user.username : '') + ')');
  }
</script></body>
</html>

由于官方源码 iframe 弹窗,所以需要把 script 标签放入 body

最后,前端把获取到的 name,last_name,等信息,全部传到后端,后端根据哈希做完整性校验,其中 botToken 就是前面拿到的 token
逻辑参考:
https://gist.github.com/MakStashkevich/7ae71729adbe3cbe2a662a7e16df6ea2


@Data
public class OauthTgDto {
    /** tg id*/
    String id;
    String firstName;
    String username;
    /** 推特头像*/
    String photoUrl;
    /** 授权时间*/
    String authDate;
    /** 验证哈希*/
    String hash;
}


    public static boolean checkTelegramAuthorization(OauthTgDto params, String botToken) throws NoSuchAlgorithmException, InvalidKeyException {
        // 构造数据字符串
        String dataCheckString = getTokenStringBuilder(params);
        // 使用 bot token 计算密钥
        MessageDigest digest = MessageDigest.getInstance("SHA-256");
        byte[] secretKey = digest.digest(botToken.getBytes(StandardCharsets.UTF_8));

        // 使用密钥计算哈希
        Mac sha256Hmac = Mac.getInstance("HmacSHA256");
        SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey, "HmacSHA256");
        sha256Hmac.init(secretKeySpec);
        byte[] computedHash = sha256Hmac.doFinal(dataCheckString.getBytes(StandardCharsets.UTF_8));

        // 将计算出的哈希值转换为 Base64 编码
        String computedHashString = bytesToHex(computedHash);

        // 比较计算的哈希和传递的哈希
        return !computedHashString.equals(params.getHash());
    }

    private static @NotNull String getTokenStringBuilder(OauthTgDto params) {
        Map<String, String> dataMap = new HashMap<>();
        dataMap.put("auth_date", params.getAuthDate());
        dataMap.put("first_name", params.getFirstName());
        dataMap.put("id", params.getId());
        dataMap.put("username", params.getUsername());
        dataMap.put("photo_url", params.getPhotoUrl());

        return   dataMap.entrySet().stream()
                .sorted(Map.Entry.comparingByKey())
                .map(entry -> entry.getKey() + "=" + entry.getValue())
                .collect(Collectors.joining("\n"));
    }
    
    private static String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02x", b));
        }
        return sb.toString();
    }
这是一段防爬代码块,我不介意文章被爬取,但请注明出处
console.log("作者主页:https://www.cnblogs.com/Go-Solo");
console.log("原文地址:https://www.cnblogs.com/Go-Solo/p/18367728");
posted @ 2024-08-19 18:37  Go_Solo  阅读(158)  评论(0编辑  收藏  举报