You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Microsoft Bot Framework SDK4 Node.js:调用Freshservice API实现客户认证咨询

Got it, let's walk through how to implement Freshservice authentication in your Bot Framework v4 bot step by step. I'll cover both C# and Node.js (the most common stacks for Bot Framework) and tie everything together with the state accessor you already set up.

1. Overall Flow Recap

First, let's align on the steps we need to execute:

  • Pull the stored user credentials (company domain, username, password) from your bot's state accessor
  • Construct a Freshservice API request with proper authentication headers
  • Send the request to validate credentials (we'll use the /api/v2/me endpoint—it returns the user's profile if auth succeeds)
  • Process the API response and send a clear result back to the Bot Framework Emulator

2. Prep Work

First, remember Freshservice uses Basic Authentication:

  • Encode the username (usually the user's email) and password into a Base64 string for the Authorization header
  • The API endpoint format is https://{your-company-domain}.freshservice.com/api/v2/me

Install any missing dependencies:

  • For C#: Ensure you have System.Net.Http, System.Text.Json, and the core Bot Framework SDK packages installed via NuGet
  • For Node.js: Install axios (for HTTP requests) if you don't have it already:
    npm install axios
    

3. Implementation (C# Example)

Step 1: Define Models for State and API Response

First, create classes to handle stored credentials and the Freshservice user response:

// Class to store user's Freshservice credentials in state
public class UserFreshserviceCredentials
{
    public string CompanyDomain { get; set; }
    public string Username { get; set; }
    public string Password { get; set; }
}

// Class to map Freshservice's /me endpoint response
public class FreshserviceUserProfile
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
    // Add other fields you need from the API response
}

Step 2: Add Auth Logic to Your Bot Class

Inject HttpClient and your state accessor into your bot, then add the authentication logic in OnTurnAsync:

private readonly IStatePropertyAccessor<UserFreshserviceCredentials> _userCredsAccessor;
private readonly HttpClient _httpClient;

public YourBotName(IStatePropertyAccessor<UserFreshserviceCredentials> userCredsAccessor, HttpClient httpClient)
{
    _userCredsAccessor = userCredsAccessor ?? throw new ArgumentNullException(nameof(userCredsAccessor));
    _httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
}

protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
    // Pull stored credentials from state
    var userCreds = await _userCredsAccessor.GetAsync(turnContext, () => new UserFreshserviceCredentials(), cancellationToken);

    // Validate we have all required info
    if (string.IsNullOrWhiteSpace(userCreds.CompanyDomain) || 
        string.IsNullOrWhiteSpace(userCreds.Username) || 
        string.IsNullOrWhiteSpace(userCreds.Password))
    {
        await turnContext.SendActivityAsync("Oops, I don't have your Freshservice credentials yet. Please share your company domain, username, and password first.", cancellationToken: cancellationToken);
        return;
    }

    // Build Freshservice API request
    var apiUrl = $"https://{userCreds.CompanyDomain}.freshservice.com/api/v2/me";
    var authBytes = Encoding.ASCII.GetBytes($"{userCreds.Username}:{userCreds.Password}");
    var authHeader = Convert.ToBase64String(authBytes);
    
    _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", authHeader);

    try
    {
        var response = await _httpClient.GetAsync(apiUrl, cancellationToken);

        if (response.IsSuccessStatusCode)
        {
            var userProfile = await response.Content.ReadFromJsonAsync<FreshserviceUserProfile>(cancellationToken: cancellationToken);
            await turnContext.SendActivityAsync($"✅ Authentication successful! Welcome, {userProfile.Name} (email: {userProfile.Email})", cancellationToken: cancellationToken);
        }
        else
        {
            var errorDetails = await response.Content.ReadAsStringAsync(cancellationToken);
            await turnContext.SendActivityAsync($"❌ Authentication failed. Status code: {response.StatusCode}. Details: {errorDetails}", cancellationToken: cancellationToken);
        }
    }
    catch (Exception ex)
    {
        await turnContext.SendActivityAsync($"⚠️ Something went wrong during authentication: {ex.Message}", cancellationToken: cancellationToken);
    }
}

Step 3: Register Dependencies in Startup.cs

Make sure to register HttpClient and your state accessor in your startup configuration:

services.AddHttpClient();
services.AddSingleton<UserState>();
services.AddSingleton(sp =>
{
    var userState = sp.GetRequiredService<UserState>();
    return userState.CreateProperty<UserFreshserviceCredentials>("UserFreshserviceCredentials");
});

4. Implementation (Node.js Example)

Step 1: Add Auth Logic to Your Bot Class

Use axios for HTTP requests and pull credentials from your state accessor:

const { ActivityHandler } = require('botbuilder');
const axios = require('axios');

class FreshserviceAuthBot extends ActivityHandler {
    constructor(userState) {
        super();
        this.userState = userState;
        this.userCredsAccessor = userState.createProperty('UserFreshserviceCredentials');

        this.onMessage(async (context, next) => {
            // Get stored credentials from state
            const userCreds = await this.userCredsAccessor.get(context, {
                companyDomain: '',
                username: '',
                password: ''
            });

            // Check if we have all required info
            if (!userCreds.companyDomain || !userCreds.username || !userCreds.password) {
                await context.sendActivity("Oops, I don't have your Freshservice credentials yet. Please share your company domain, username, and password first.");
                await next();
                return;
            }

            // Build API request
            const apiUrl = `https://${userCreds.companyDomain}.freshservice.com/api/v2/me`;
            const authHeader = Buffer.from(`${userCreds.username}:${userCreds.password}`).toString('base64');

            try {
                const response = await axios.get(apiUrl, {
                    headers: { Authorization: `Basic ${authHeader}` }
                });

                const userProfile = response.data;
                await context.sendActivity(`✅ Authentication successful! Welcome, ${userProfile.name} (email: ${userProfile.email})`);
            } catch (error) {
                let errorMsg = "❌ Authentication failed: ";
                if (error.response) {
                    errorMsg += `Status code ${error.response.status}. Details: ${JSON.stringify(error.response.data)}`;
                } else {
                    errorMsg += error.message;
                }
                await context.sendActivity(errorMsg);
            }

            await next();
        });

        // Save state after each turn
        this.onDialog(async (context, next) => {
            await this.userState.saveChanges(context);
            await next();
        });
    }
}

module.exports.FreshserviceAuthBot = FreshserviceAuthBot;

Step 2: Configure State in Your Entry File (index.js)

Set up memory storage and user state for your bot:

const { BotFrameworkAdapter, MemoryStorage, UserState } = require('botbuilder');
const { FreshserviceAuthBot } = require('./freshserviceAuthBot');

// Initialize adapter
const adapter = new BotFrameworkAdapter({
    appId: process.env.MICROSOFT_APP_ID,
    appPassword: process.env.MICROSOFT_APP_PASSWORD
});

// Initialize storage and state
const memoryStorage = new MemoryStorage();
const userState = new UserState(memoryStorage);
const bot = new FreshserviceAuthBot(userState);

// Process incoming requests
adapter.processActivity(req, res, async (context) => {
    await bot.run(context);
});

5. Test in Bot Framework Emulator

  1. Ensure you've already collected and stored the user's credentials in state via your conversation flow
  2. Start your bot and connect the emulator
  3. Send a message to trigger the authentication logic—you'll see a clear success/failure message in the chat window

Important Notes

  • Security Warning: Storing plaintext passwords in state is not safe for production. Consider switching to Freshservice API keys or implementing an OAuth2 flow instead of storing user passwords directly.
  • Rate Limits: Freshservice has API rate limits—make sure your bot handles 429 (Too Many Requests) errors gracefully if you're making multiple calls.

内容的提问来源于stack exchange,提问作者Divyansh Badonia

火山引擎 最新活动