Pāriet uz saturu

Autentifikācija

SMSBAT ChatHub API izmanto divu līmeņu JWT marķieru autentifikācijas sistēmu ar uzņēmuma marķieriem un operatora pilnvarām.

Autentifikācijas plūsma

graph TD
    A[Login Credentials] --> B[Get Company Token]
    B --> C[Use Company Token]
    C --> D[Get Operator Token]
    D --> E[Use Operator Token]
    E --> F[Validate Token]

Uzņēmuma marķieris

Uzņēmuma pilnvaras nodrošina organizācijas līmeņa piekļuvi ChatHub API.

Iegūstiet uzņēmuma marķieri

Beigu punkts: POST /api/company/get-token

Pieprasījums:

curl -X POST https://chatapi.smsbat.com/api/company/get-token \
  -H "Content-Type: application/json" \
  -d '{
    "login": "your-company-login",
    "password": "your-company-password"
  }'

Pieprasījuma struktūra:

{
  "login": "string",
  "password": "string"
}

Atbilde:

"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"

Atbilde ir JWT marķiera virkne.

Izmantojiet uzņēmuma marķieri

Iekļaujiet uzņēmuma pilnvaru API pieprasījumos, izmantojot vienu no divām metodēm:

1. metode: autorizācijas galvene (ieteicams)

curl -X GET https://chatapi.smsbat.com/api/company/organization \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."

2. metode: X-Authorization-Key galvene

curl -X GET https://chatapi.smsbat.com/api/company/organization \
  -H "X-Authorization-Key: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."

Operatora marķieris

Operatoru marķieri nodrošina lietotājam raksturīgu piekļuvi atsevišķiem operatoriem organizācijā.

Iegūstiet operatora pilnvaru

Beigu punkts: POST /api/operator/get-token

Pieprasījums:

curl -X POST https://chatapi.smsbat.com/api/operator/get-token \
  -H "Authorization: Bearer {company-token}" \
  -H "Content-Type: application/json" \
  -d '{
    "id": 123,
    "expiresAt": "2025-12-31T23:59:59Z"
  }'

Pieprasījuma struktūra:

{
  "id": 0,
  "expiresAt": "2025-01-20T14:33:34.147Z"
}

Parametri:

Parametrs Tips Nepieciešams Apraksts
"id" vesels skaitlis Operatora ID
beidzas virkne (ISO 8601) Žetona derīguma termiņš un laiks (maks. 24 stundas no šī brīža)

Svarīgi! Maksimālais marķiera kalpošanas laiks ir 24 stundas. Parametrs "expiresAt" nedrīkst būt ilgāks par 24 stundām nākotnē.

Atbilde:

"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcGVyYXRvcl9pZCI6MTIzLCJleHAiOjE3Mzc0MTI3OTl9.example_signature"

Izmantojiet operatora marķieri

API pieprasījumos iekļaujiet operatora pilnvaru:

curl -X GET https://chatapi.smsbat.com/api/operator \
  -H "Authorization: Bearer {operator-token}"

Token Validation

Pirms lietošanas pārbaudiet, vai marķieris joprojām ir derīgs.

Beigu punkts: POST /api/operator/validate-token

Pieprasījums:

curl -X POST https://chatapi.smsbat.com/api/operator/validate-token \
  -H "Authorization: Bearer {company-token}" \
  -H "Content-Type: application/json" \
  -d '{
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
  }'

Pieprasījuma struktūra:

{
  "token": "string"
}

Atbilde (derīgs marķieris):

{
  "isValid": true,
  "operatorId": 123,
  "clientId": 0,
  "expiresAt": "2025-12-31T23:59:59Z",
  "error": null
}

Atbilde (nederīgs marķieris):

{
  "isValid": false,
  "error": "Invalid token"
}

Žetona derīguma termiņš

Uzņēmuma žetoni

  • API nav skaidra derīguma termiņa
  • Sazinieties ar sava konta pārzini, lai uzzinātu marķiera dzīves cikla politikas
  • Drošības nolūkos periodiski pagrieziet žetonus

Operatora marķieri

  • Derīguma termiņš iestatīts, pieprasot pilnvaru (parametrs "expiresAt")
  • Pirms lietošanas apstipriniet žetonus
  • Pieprasiet jaunus žetonus pirms derīguma termiņa beigām

Īstenošanas piemēri

Python

import requests
from datetime import datetime, timedelta

class ChatHubAuth:
    def __init__(self, base_url):
        self.base_url = base_url
        self.company_token = None
        self.operator_tokens = {}

    def get_company_token(self, login, password):
        """Get company authentication token"""
        response = requests.post(
            f"{self.base_url}/api/company/get-token",
            json={"login": login, "password": password}
        )
        response.raise_for_status()
        self.company_token = response.json()
        return self.company_token

    def get_operator_token(self, operator_id, expires_days=30):
        """Get operator token with expiration"""
        expires_at = (
            datetime.utcnow() + timedelta(days=expires_days)
        ).isoformat() + "Z"

        response = requests.post(
            f"{self.base_url}/api/operator/get-token",
            headers={"Authorization": f"Bearer {self.company_token}"},
            json={"id": operator_id, "expiresAt": expires_at}
        )
        response.raise_for_status()

        token = response.json()
        self.operator_tokens[operator_id] = token
        return token

    def validate_token(self, token):
        """Validate if token is still valid"""
        response = requests.post(
            f"{self.base_url}/api/operator/validate-token",
            headers={"Authorization": f"Bearer {self.company_token}"},
            json={"token": token}
        )
        response.raise_for_status()
        return response.json()

# Usage
auth = ChatHubAuth("https://chatapi.smsbat.com")

# Get company token
company_token = auth.get_company_token("login", "password")

# Get operator token
operator_token = auth.get_operator_token(operator_id=123, expires_days=30)

# Validate token
is_valid = auth.validate_token(operator_token)
print(f"Token valid: {is_valid['valid']}")

JavaScript (Node.js)

const axios = require('axios');

class ChatHubAuth {
  constructor(baseUrl) {
    this.baseUrl = baseUrl;
    this.companyToken = null;
    this.operatorTokens = {};
  }

  async getCompanyToken(login, password) {
    const response = await axios.post(
      `${this.baseUrl}/api/company/get-token`,
      { login, password }
    );

    this.companyToken = response.data;
    return this.companyToken;
  }

  async getOperatorToken(operatorId, expiresDays = 30) {
    const expiresAt = new Date(
      Date.now() + expiresDays * 24 * 60 * 60 * 1000
    ).toISOString();

    const response = await axios.post(
      `${this.baseUrl}/api/operator/get-token`,
      { id: operatorId, expiresAt },
      {
        headers: {
          Authorization: `Bearer ${this.companyToken}`
        }
      }
    );

    const token = response.data;
    this.operatorTokens[operatorId] = token;
    return token;
  }

  async validateToken(token) {
    const response = await axios.post(
      `${this.baseUrl}/api/operator/validate-token`,
      { token },
      {
        headers: {
          Authorization: `Bearer ${this.companyToken}`
        }
      }
    );

    return response.data;
  }
}

// Usage
const auth = new ChatHubAuth('https://chatapi.smsbat.com');

async function authenticate() {
  // Get company token
  const companyToken = await auth.getCompanyToken('login', 'password');

  // Get operator token
  const operatorToken = await auth.getOperatorToken(123, 30);

  // Validate token
  const validation = await auth.validateToken(operatorToken);
  console.log('Token valid:', validation.isValid);
}

authenticate();

PHP

<?php

class ChatHubAuth {
    private $baseUrl;
    private $companyToken;
    private $operatorTokens = [];

    public function __construct($baseUrl) {
        $this->baseUrl = $baseUrl;
    }

    public function getCompanyToken($login, $password) {
        $ch = curl_init($this->baseUrl . '/api/company/get-token');

        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'Content-Type: application/json'
        ]);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
            'login' => $login,
            'password' => $password
        ]));

        $response = curl_exec($ch);
        curl_close($ch);

        $this->companyToken = json_decode($response);
        return $this->companyToken;
    }

    public function getOperatorToken($operatorId, $expiresDays = 30) {
        $expiresAt = date(
            'Y-m-d\TH:i:s\Z',
            time() + ($expiresDays * 24 * 60 * 60)
        );

        $ch = curl_init($this->baseUrl . '/api/operator/get-token');

        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'Content-Type: application/json',
            'Authorization: Bearer ' . $this->companyToken
        ]);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
            'id' => $operatorId,
            'expiresAt' => $expiresAt
        ]));

        $response = curl_exec($ch);
        curl_close($ch);

        $token = json_decode($response);
        $this->operatorTokens[$operatorId] = $token;
        return $token;
    }

    public function validateToken($token) {
        $ch = curl_init($this->baseUrl . '/api/operator/validate-token');

        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'Content-Type: application/json',
            'Authorization: Bearer ' . $this->companyToken
        ]);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
            'token' => $token
        ]));

        $response = curl_exec($ch);
        curl_close($ch);

        return json_decode($response, true);
    }
}

// Usage
$auth = new ChatHubAuth('https://chatapi.smsbat.com');

// Get company token
$companyToken = $auth->getCompanyToken('login', 'password');

// Get operator token
$operatorToken = $auth->getOperatorToken(123, 30);

// Validate token
$validation = $auth->validateToken($operatorToken);
echo "Token valid: " . ($validation['isValid'] ? 'Yes' : 'No');

Labākā prakse

Žetonu krātuve

  • ✅ Droši glabājiet žetonus (šifrēta datu bāze, noslēpumu pārvaldnieks)
  • ✅ Nekad nepiešķiriet marķierus versiju kontrolei
  • ✅ Akreditācijas datiem izmantojiet vides mainīgos
  • ❌ Neglabājiet žetonus vienkāršā tekstā
  • ❌ Neatklājiet žetonus klienta puses kodā

Žetonu rotācija

  • Periodiski mainiet uzņēmuma žetonus (ik pēc 3–6 mēnešiem)
  • Iestatiet saprātīgu operatora žetonu derīguma termiņu (7–30 dienas)
  • Ieviesiet automātisku marķiera atsvaidzināšanu pirms derīguma termiņa beigām
  • Atsaukt žetonus, kad operatori aiziet

Kļūdu apstrāde

async function authenticateWithRetry(login, password, retries = 3) {
  for (let i = 0; i < retries; i++) {
    try {
      return await getCompanyToken(login, password);
    } catch (error) {
      if (error.response?.status === 401) {
        throw new Error('Invalid credentials');
      }

      if (i === retries - 1) throw error;

      // Wait before retry
      await new Promise(resolve =>
        setTimeout(resolve, Math.pow(2, i) * 1000)
      );
    }
  }
}

Token Validation

Vienmēr apstipriniet marķierus pirms kritiskām darbībām:

async function performSecureOperation(token, operation) {
  // Validate token first
  const validation = await validateToken(token);

  if (!validation.isValid) {
    throw new Error('Token expired or invalid');
  }

  // Proceed with operation
  return await operation();
}

Drošības apsvērumi

Tikai HTTPS

Vienmēr izmantojiet HTTPS, nosūtot autentifikācijas pieprasījumus:

// ✅ Correct
const baseUrl = 'https://chatapi.smsbat.com';

// ❌ Wrong - never use HTTP for authentication
const baseUrl = 'http://api.chathub.smsbat.com';

Tokena darbības joma

Katrai darbībai izmantojiet atbilstošo marķieri:

  • Uzņēmuma marķieris: organizācijas vadība, operatora izveide
  • Operatora marķieris: tērzēšanas darbības, ziņojumu apstrāde

Likmes ierobežojums

Ieviest ātruma ierobežojumu autentifikācijas pieprasījumiem:

class RateLimitedAuth {
  constructor() {
    this.lastRequest = 0;
    this.minInterval = 1000; // 1 second between requests
  }

  async getToken(login, password) {
    const now = Date.now();
    const timeSinceLastRequest = now - this.lastRequest;

    if (timeSinceLastRequest < this.minInterval) {
      await new Promise(resolve =>
        setTimeout(resolve, this.minInterval - timeSinceLastRequest)
      );
    }

    this.lastRequest = Date.now();
    return await makeAuthRequest(login, password);
  }
}

Traucējummeklēšana

401 Nesankcionēts

  • Pārbaudiet, vai akreditācijas dati ir pareizi
  • nav beidzies čeka marķiera derīguma termiņš
  • Pārliecinieties, vai pieprasījuma galvenēs ir iekļauts marķieris
  • Apstiprināt marķiera formātu

403 Aizliegts

- Pārbaudiet, vai marķierim ir nepieciešamās atļaujas - Pārbaudiet, vai tiek izmantots pareizais marķiera veids (uzņēmums pret operatoru) - Pārliecinieties, vai marķieris nav atsaukts

Token beidzies

  • Pieprasīt jaunu marķieri
  • Ieviesiet automātisku marķiera atsvaidzināšanu
  • Iestatiet atbilstošus derīguma termiņus

Nākamie soļi