typescript - Collecting user account security token from within a visual studio code extension - Stack Overflow

admin2025-05-01  1

My Visual Studio Code extension is written in typescript, which I am just learning.

When the extension is initailized I want to open a webview panel (or a separate browser - if i can't get a webview to work - but that is a different question) and point it to my company's login page. When the user enters valid credentials the page is replaced with a callback page - and the url briefly includes the token info.

In C# (for a visual studio extension) I do that with a straight forward navigationcomplete event handler. I check for a certain string in the url, and if it is there I parse out the information I need.

In typescript my event handler is not picking up the event, and so I never gets the information I need.

I cannot see what i am doing wrong - and really appreciate any help.

Here is my current code in the 2 key files: the extension.ts and the showLoginWindow.ts file. I am showing it here with irrelevant stuff cut out. You'll see that I want to return my token info in a class object called TokenResponse. I didn't include that class because it is pretty obvious.

Here's the extension.ts file:

// Import the module and reference it with the alias vscode in your code below
import * as vscode from 'vscode';
import { showLoginWindow } from './helpers/showLoginWindow';
import { baseWebUrl } from './helpers/TokenUtils';

export async function activate(context: vscode.ExtensionContext) {
    console.log('Congratulations, your extension "xyz" is now active!');

const targetUrl =  loginUrl;
try {
  const tokeninfo = await showLoginWindow(targetUrl);
} catch (error) {

  console.error(error);

}

export function deactivate() {}

Here's the showLoginWindow.ts file:

import * as vscode from 'vscode';
import { TokenResponse } from '../classes/tokenResponse';
import { baseWebUrl } from '../helpers/TokenUtils';
import path from 'path';

export function showLoginWindow(context: vscode.ExtensionContext, targetUrl: string): Promise<TokenResponse> {
    return new Promise((resolve, reject) => {
        const panel = vscode.window.createWebviewPanel(
            'loginWindow',
            'Website Login',
            vscode.ViewColumn.One,
            {
                enableScripts: true,
                localResourceRoots: [vscode.Uri.file(path.join(context.extensionPath, 'src/scripts'))] 
            }
        );

        panel.webview.html = getWebviewContent(targetUrl);

        // Handle messages from the webview
        panel.webview.onDidReceiveMessage(
            message => {
                console.log('Received message from webview:', message);
                switch (messagemand) {
                    case 'urlChanged':
                        const currentUrl = message.url;
                        if (currentUrl.includes("extension-callback")) {
                            const splitChar = currentUrl.includes("#") ? '#' : '?';
                            const fragment = currentUrl.split(splitChar).pop();
                            if (fragment) {
                                const queryParams = new URLSearchParams(fragment);
                                const accessToken = queryParams.get("access_token") || '';
                                const expiresAt = queryParams.get("expires_at") || '0';
                                const expiresIn = queryParams.get("expires_in") || '0';
                                const providerToken = queryParams.get("provider_token") || '';
                                const refreshToken = queryParams.get("refresh_token") || '';
                                const tokenType = queryParams.get("token_type") || '';

                                const expiryAt = parseInt(expiresAt, 10);
                                const expirySeconds = parseInt(expiresIn, 10);

                                const newTokenResponse = new TokenResponse(
                                    accessToken,
                                    expiryAt,
                                    expirySeconds,
                                    refreshToken,
                                    tokenType
                                );

                                // Resolve the promise with the new token response
                                resolve(newTokenResponse);

                                // Close the panel
                                panel.dispose();
                            }
                        }
                        break;
                }
            },
            undefined,
            context.subscriptions
        );
    });
}

function getWebviewContent(targetUrl: string): string {
    return `
        <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <title>Login</title>
        </head>
        <body>
            <iframe id="loginFrame" src="${targetUrl}" width="100%" height="800px"></iframe>
            <script>
                const vscode = acquireVsCodeApi();
                let lastUrl = '';

                document.getElementById('loginFrame').onload = function() {
                    const iframe = document.getElementById('loginFrame');

                    // Use setInterval to check for URL changes
                    setInterval(() => {
                        try {
                            const currentUrl = iframe.contentWindow.location.href;
                            if (currentUrl !== lastUrl) {
                                lastUrl = currentUrl;
                                console.log('Sending message to VS Code extension');
                                vscode.postMessage({
                                    command: 'urlChanged',
                                    url: currentUrl
                                });
                            }
                        } catch (e) {
                            // Handle cross-origin access error
                            console.error('Error accessing iframe content:', e);
                        }
                    }, 1000); // Check every second
                };
            </script>
        </body>
        </html>
    `;
}



function handleLoginSuccess(tokenResponse: TokenResponse) {
    vscode.window.showInformationMessage('Login succeeded!');
    // Here you can handle the token response, e.g., store it or use it as needed
    console.log('Token Response:', tokenResponse);
}
转载请注明原文地址:http://anycun.com/QandA/1746095306a91599.html