使用BotAuth Node.js为Microsoft Bot Framework添加自定义第三方登录提供商
用BotAuth Node.js实现自定义第三方认证提供商(附替代方案)
当然可以用BotAuth实现自定义提供商!我之前在基于Node.js的Bot Framework项目里做过类似需求,下面给你详细说怎么操作,另外也会推荐更现代的替代方案——毕竟BotAuth的维护已经有些年头了。
一、用BotAuth实现自定义提供商
BotAuth的核心是通过OAuth2Provider类封装不同的OAuth2提供商,我们只需要继承这个类,根据目标第三方API的认证规则重写必要方法就行:
1. 创建自定义提供商类
新建一个CustomOAuthProvider.js文件,实现自己的提供商逻辑:
const { OAuth2Provider } = require('botauth'); class CustomProvider extends OAuth2Provider { constructor(settings) { super(settings); // 替换成你的第三方API认证端点 this.authUrl = 'https://your-custom-api.com/oauth/authorize'; // 替换成你的第三方API Token获取端点 this.tokenUrl = 'https://your-custom-api.com/oauth/token'; // 默认权限范围,可通过settings覆盖 this.scope = settings.scope || 'basic_access'; } // 重写生成授权URL的方法,适配目标API参数要求 getAuthorizationUrl(session, state) { const params = { client_id: this.clientId, redirect_uri: this.redirectUri, scope: this.scope, state: state, response_type: 'code' // 大多数OAuth2用code模式 }; // 拼接参数到授权URL const url = new URL(this.authUrl); Object.keys(params).forEach(key => url.searchParams.append(key, params[key])); return url.toString(); } // 重写获取Token的方法,适配目标API请求格式 async getToken(code) { const params = new URLSearchParams(); params.append('grant_type', 'authorization_code'); params.append('code', code); params.append('client_id', this.clientId); params.append('client_secret', this.clientSecret); params.append('redirect_uri', this.redirectUri); const response = await fetch(this.tokenUrl, { method: 'POST', body: params, headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }); if (!response.ok) { throw new Error(`获取Token失败: ${response.statusText}`); } return response.json(); } } module.exports = CustomProvider;
2. 在Bot中注册并使用自定义提供商
在你的Bot主文件里初始化BotAuth,添加自定义提供商,并在对话中触发认证:
const BotAuth = require('botauth'); const CustomProvider = require('./CustomProvider'); const builder = require('botbuilder'); // 初始化Bot连接器 const connector = new builder.ChatConnector({ appId: process.env.MICROSOFT_APP_ID, appPassword: process.env.MICROSOFT_APP_PASSWORD }); // 初始化BotAuth const botauth = new BotAuth({ secret: 'your-random-bot-secret', // 用于加密状态的密钥 baseUrl: 'https://your-bot-deployment-url.com' // 你的Bot公网地址 }); // 注册自定义提供商 botauth.provider('custom-api', new CustomProvider({ clientId: 'your-custom-api-client-id', clientSecret: 'your-custom-api-client-secret', redirectUri: 'https://your-bot-deployment-url.com/api/oauth/custom-api/callback', scope: 'read write' })); // 创建Bot实例 const bot = new builder.UniversalBot(connector); // 添加登录对话 bot.dialog('/login', [ async (session) => { // 触发自定义提供商的认证流程 await botauth.authenticate(session, 'custom-api', (err, user) => { if (err) { session.send(`登录出错了:${err.message}`); } else { session.send(`登录成功!你的Token是:${user.accessToken}`); // 这里就可以用user.accessToken调用第三方API了 } }); } ]); // 设置默认对话 bot.dialog('/', (session) => { session.send('欢迎!输入「登录」开始认证'); session.beginDialog('/login'); });
3. 配置回调路由
BotAuth需要处理第三方API的回调请求,所以在你的Express/Restify服务器中添加路由:
const express = require('express'); const server = express(); // 处理Bot的消息请求 server.post('/api/messages', connector.listen()); // 处理OAuth回调 server.post('/api/oauth/:provider/callback', (req, res) => { botauth.handleCallback(req, res, (err, user) => { if (err) { return res.status(500).send(`认证回调出错:${err.message}`); } // 重定向回Bot聊天窗口 res.redirect(`https://webchat.botframework.com/redirect?state=${req.query.state}`); }); }); server.listen(process.env.PORT || 3978, () => { console.log('Bot服务器已启动'); });
二、更现代的替代方案:使用Bot Framework v4的OAuthPrompt
如果你用的是Bot Framework v4+(现在推荐的版本),BotAuth其实已经有点过时了,官方提供的OAuthPrompt是更合适的选择,它原生支持自定义OAuth2提供商:
1. 配置自定义连接
你可以在Bot Framework Portal的「连接设置」里添加自定义OAuth2连接,填写第三方API的:
- 授权端点URL
- Token端点URL
- Client ID/Secret
- 权限范围等信息
2. 在对话中使用OAuthPrompt
const { ActivityHandler, OAuthPrompt, WaterfallDialog, DialogSet } = require('botbuilder'); class CustomAuthBot extends ActivityHandler { constructor(conversationState, userState) { super(); this.conversationState = conversationState; this.userState = userState; this.dialogState = this.conversationState.createProperty('DialogState'); this.dialogs = new DialogSet(this.dialogState); // 添加OAuthPrompt,指定自定义连接名称 this.dialogs.add(new OAuthPrompt('CustomAuthPrompt', { connectionName: 'YourCustomOAuthConnection', text: '请登录你的自定义账号', title: '自定义账号登录', timeout: 300000 // 5分钟超时 })); // 添加瀑布对话处理认证流程 this.dialogs.add(new WaterfallDialog('LoginDialog', [ async (step) => { // 触发登录提示 return await step.beginDialog('CustomAuthPrompt'); }, async (step) => { const tokenResponse = step.result; if (tokenResponse) { await step.context.sendActivity('登录成功!'); // 使用tokenResponse.token调用第三方API const apiResponse = await fetch('https://your-custom-api.com/data', { headers: { 'Authorization': `Bearer ${tokenResponse.token}` } }); const data = await apiResponse.json(); await step.context.sendActivity(`获取到的数据:${JSON.stringify(data)}`); } else { await step.context.sendActivity('登录失败,请重试。'); } return await step.endDialog(); } ])); // 处理用户消息 this.onMessage(async (context, next) => { const dc = await this.dialogs.createContext(context); if (context.activity.text.includes('登录')) { await dc.beginDialog('LoginDialog'); } else { await context.sendActivity('输入「登录」开始认证流程'); } await this.conversationState.saveChanges(context); await next(); }); } } module.exports.CustomAuthBot = CustomAuthBot;
这种方式不需要自己封装提供商类,直接通过配置连接就能实现自定义认证,而且完全贴合Bot Framework的最新生态,维护性更好。
内容的提问来源于stack exchange,提问作者prtdomingo
相关产品推荐
相关产品推荐

