繁体   English   中英

使用带有 Spring Security 的 Telegram 登录

[英]Login with Telegram with Spring Security

我正在尝试在我的 Spring Boot 应用程序上使用 Telegram ( https://core.telegram.org/widgets/login ) 实现登录,但遇到了一个问题。

我一直在尝试实现他们提供的 PHP 代码来验证身份验证,但是出了点问题,我不明白是什么。

所以,这就是 PHP 上的代码

secret_key = SHA256(<bot_token>)
if (hex(HMAC_SHA256(data_check_string, secret_key)) == hash) {
  // data is from Telegram
}

数据检查字符串是所有接收到的字段的串联,按字母顺序排序,格式为key=<value> ,换行符 ('\\n', 0xA0) 用作分隔符 - 例如, 'auth_date=<auth_date>\\nfirst_name=<first_name>\\nid=<id>\\nusername=<username>

所以,我所做的是:

@AllArgsConstructor
@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
public class AuthenticationRequest {

  @NotNull
  private Long authDate;

  private String firstName;

  @NotEmpty
  private String id;

  private String lastName;

  private String photoUrl;

  private String username;

  @NotEmpty
  private String hash;

  @Override
  public String toString() {
    final var data = new StringBuilder();

    for (final Field field : getClass().getDeclaredFields()) {
      try {
        if (!field.getName().equals("hash") && field.get(this) != null) {
          final var fieldName = CaseFormat.LOWER_CAMEL
              .to(CaseFormat.LOWER_UNDERSCORE, field.getName());
          data.append(fieldName).append("=").append(field.get(this)).append("\\n");
        }
      } catch (IllegalAccessException e) {
        e.printStackTrace();
      }
    }

    return data.substring(0, data.length() - 2);
  }
}

以及这两种方法:

private static String hmacSha256(final String data, final byte[] secret) {
    try {
      Mac sha256Hmac = Mac.getInstance("HmacSHA256");
      SecretKeySpec secretKey = new SecretKeySpec(secret, "HmacSHA256");
      sha256Hmac.init(secretKey);

      byte[] signedBytes = sha256Hmac.doFinal(data.getBytes());

      return bytesToHex(signedBytes);
    } catch (NoSuchAlgorithmException | InvalidKeyException ex) {
      return null;
    }
  }

  private static String bytesToHex(byte[] hash) {
    StringBuilder hexString = new StringBuilder();
    for (final byte b : hash) {
      String hex = Integer.toHexString(0xff & b);
      if (hex.length() == 1) {
        hexString.append('0');
      }
      hexString.append(hex);
    }
    return hexString.toString();
  }

当我比较它们时,它们是完全不同的两个字符串

final var telegramData = authenticationRequest.toString();
final var digest = MessageDigest.getInstance("SHA-256");
final var hashedToken = digest.digest(botToken.getBytes());

System.out.println(authenticationRequest.getHash());
System.out.println(hmacSha256(telegramData, hashedToken));

你能告诉我我做错了什么吗? 也许我完全误解了我必须验证身份验证数据的方式,或者我错过了什么?

试试这个,代码有点丑,但效果很好!

public boolean verifyAuth(JsonObject Telegram_User){

    String hash = Telegram_User.remove("hash").getAsString();

    try {
        Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
        String[] t = Telegram_User.toString().replace("{","").replace("}","").replace("\":","=").replace(",","\n").replace("\"","").split("\n");
        sha256_HMAC.init(new SecretKeySpec(MessageDigest.getInstance("SHA-256").digest(BezouroBot.telegram.getBotToken().getBytes(StandardCharsets.UTF_8)),"SHA256"));

        Arrays.sort(t);
        StringBuilder i = new StringBuilder();
        boolean First = true;

        for (String s : t) if(First){ First = false; i = new StringBuilder(s);} else i.append("\n").append(s);

        return Hex.encodeHexString(sha256_HMAC.doFinal(i.toString().getBytes())).equals(hash);

    } catch (NoSuchAlgorithmException | InvalidKeyException e) {
        e.printStackTrace();
        return false;
    }

}

这是我的工具

// define your token to a variable
private final String TELEGRAM_TOKEN = ""

@PostMapping("auth/telegram")
public ResponseEntity<Object> telegramAuth(@RequestBody Map<String, Object> request) {
    String hash = (String) request.get("hash");
    request.remove("hash");

    // Prepare the string
    String str = request.entrySet().stream()
            .sorted((a, b) -> a.getKey().compareToIgnoreCase(b.getKey()))
            .map(kvp -> kvp.getKey() + "=" + kvp.getValue())
            .collect(Collectors.joining("\n"));

    try {
        SecretKeySpec sk = new SecretKeySpec(
                // Get SHA 256 from telegram token
                MessageDigest.getInstance("SHA-256").digest(TELEGRAM_TOKEN.getBytes(StandardCharsets.UTF_8)
                ), "HmacSHA256");
        Mac mac = Mac.getInstance("HmacSHA256");
        mac.init(sk);

        byte[] result = mac.doFinal(str.getBytes(StandardCharsets.UTF_8));

        // Convert the result to hex string
        // Like https://stackoverflow.com/questions/9655181
        String resultStr = ByteBufUtil.bytesToHex(result);

        // Compare the result with the hash from body
        if(hash.compareToIgnoreCase(resultStr) == 0) {

            // Do other things like create a user and JWT token
            return ResponseEntity.ok("ok");
        } else {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).body(
                    new MessageResponse("Login info hash mismatch")
            );
        }
    } catch (Exception e) {
        logger.error(e.getMessage(), e);
        return ResponseEntity.status(HttpStatus.FORBIDDEN).body(
                new MessageResponse("Server error while authenticating")
        );
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM