如何在 TypeScript React 单页应用中正确导入和使用 MSAL(Microsoft Authentication Library for js)?

25

问题

我似乎无法在我的 TypeScript 代码中正确导入 MSAL 库。我正在使用 MSAL for JS 库(应该有类型声明),在一个使用 create-react-app with react-typescript 脚本构建的简单 TypeScript/React 项目中。我对 TypeScript 不太熟悉,不确定是否遗漏了一些明显的东西,或者在使用 TypeScript 项目时存在 MSAL 包的问题。

详情:

  1. 我使用 npm install --save msal 命令从 NPM 安装了 MSAL 包。
  2. 我尝试使用不同形式的 import {Msal} from 'msal'; 将 MSAL 导入到我的 .ts 文件中。
  3. 这会导致 TypeScript 错误:Could not find a declaration file for module 'msal'. '<path>/node_modules/msal/out/msal.js' implicitly has an 'any' type.
  4. 我认为这很奇怪,于是查看了 node_module/msal/out 文件夹并看到了一个名为“msal.d.ts”的文件,这是我期望看到的。
  5. 当我查看msal.d.ts 文件的内容时,我没有看到任何导出,而我通常希望看到导出。
  6. 我尝试使用 npm install --save-dev @types/msal 命令从 @types 中安装声明文件,但是没有找到该文件。
  7. 我还尝试使用 let Msal = require('Msal'); 将其导入到我的文件中,但是会出现 Msal.UserAgentApplication 不是构造函数的错误。
  8. 我尝试使用 /// 参考指令并将一个脚本标签添加到主 index.html 中,但是不太感觉这是解决问题的正确方法。

示例 ExampleMsal.ts

import { observable, action, computed } from 'mobx';
import * as Msal from 'msal'; // <-- This line gives the error

class ExampleMsal{
    @observable 
    private _isLoggedIn: boolean;

    constructor() {
        this._isLoggedIn = false;
    }

    @computed 
    get isLoggedIn(): boolean {
        return this._isLoggedIn;
    }

    @action 
    signIn() {

        let userAgentApplication = new Msal.UserAgentApplication('<client-id>', null, 
        function (errorDes: string, token: string, error: string, tokenType: string) {
            // this callback is called after loginRedirect OR acquireTokenRedirect 
            // (not used for loginPopup/aquireTokenPopup)
        }
        );

        userAgentApplication.loginPopup(['user.read']).then(function(token: string) {
            let user = userAgentApplication.getUser();
            if (user) {
                // signin successful
                alert('success');
            } else {
                // signin failure
                alert('fail');
            }
        }, function (error: string) {
            // handle error
            alert('Error' + error);
        });        
        this._isLoggedIn = true;
    }

    @action 
    signOut() {
        this._isLoggedIn = false;
    }
}

export default ExampleMsal;

tsconfig.json

{
  "compilerOptions": {
    "outDir": "build/dist",
    "module": "commonjs",
    "target": "es5",
    "lib": ["es6", "dom"],
    "sourceMap": true,
    "allowJs": true,
    "jsx": "react",
    "moduleResolution": "node",
    "rootDir": "src",
    "forceConsistentCasingInFileNames": true,
    "noImplicitReturns": true,
    "noImplicitThis": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "suppressImplicitAnyIndexErrors": true,
    "noUnusedLocals": true,
    "experimentalDecorators": true
  },
  "exclude": [
    "node_modules",
    "build",
    "scripts",
    "acceptance-tests",
    "webpack",
    "jest",
    "src/setupTests.ts"
  ],
  "types": [
    "typePatches"
  ]
}
4个回答

16

看起来最新版本的MSAL.js 确实有一个CommonJS导出。您现在可以在TypeScript中执行以下操作(已测试TypeScript版本2.3.3和MSAL.js版本0.1.3):

import * as Msal from 'msal';

现在您可以在您的.ts(或者在我的情况下是.tsx文件)中设置一个点击事件处理程序并创建一个UserAgentApplication对象:

// In you class somewhere
private userAgentApplication: any = undefined;

// The login button click handler
handleLoginClick = (event: any): void => {
    if (!this.userAgentApplication) {
        this.userAgentApplication = new Msal.UserAgentApplication(
            'clientID string', 'authority string or empty', this.authCallback, { cacheLocation: 'localStorage'});
    }
    // Other login stuff...
}

// In React render()
public render() {
    return (
        <Button
            bsStyle="warning"
            type="button"
            onClick={(e) => this.handleLoginClick(e)}
        >
        Log in
        </Button>
    );
}

我已经根据您的建议成功创建了一个"UserAgentApplication"对象。但是,在之前的代码中(其中我从CDN加载Msai),我使用了以下语句: "Msal.Storage("localStorage").getItem(...)"。但现在在我使用"import * as Msal from 'msal'"时会有错误。请问是否有一种方法可以解决这个问题? - RHarris

13

正如您所正确提到的-在msal.d.ts中没有exports-它不是一个模块,因此您不应尝试导入它。

相反,您可以像这样使用它:

/// <reference path="./node_modules/msal/out/msal.d.ts" />

const userAgentApplication = new Msal.UserAgentApplication("your_client_id", null, (errorDes, token, error, tokenType) =>
    {

    });

请注意,即使在自述文件中,他们也只指定了一种使用他们的库的方式 - 通过包含脚本标记,而不是导入模块。进一步查看他们的源代码显示,他们也没有使用模块。


参考路径定义结合在我的index.html中包含CDN的js文件,让它对我起作用了。如果我找到更清晰的方法,我会再更新的。 - nbrowne
嗨,尼格尔,你能把你的项目上传到Github吗?我正在寻找使用React和MSAL的示例。提前感谢。 - Thiago Custodio
10
MSAL的较新版本现在似乎运行良好,我正在使用0.1.3版本,只需简单地使用 import * as Msal from 'msal'; 即可。请注意不要改变原意,使翻译流畅易懂。 - StephenD

10

3
您先生是一个英雄。 - Dibran

6
如果您安装了exports-loader (npm install exports-loader --save-dev),那么您可以避免使用脚本标签,并将以下内容添加到指令中:
var Msal = require("exports-loader?Msal!../../../node_modules/msal/out/msal.js"); 

我遇到了异常: 在'exports-loader?Msal!./node_modules/msal/out/msal.js'中出现了意外的'!'。不要使用导入语法来配置webpack加载器import/no-webpack-loader-syntax。 - Paweł Skorupiński
1
我能够使用这个导入,但是我遇到了以下错误:Msal.UserAgentApplication不是构造函数 - Jed

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接