使用自定义服务进行身份验证

问题描述 投票:0回答:1

我正在尝试在 Vue2 应用程序中使用 azure-msal-browser 包实现登录。

即使在检查了几个不同的教程后,我仍然很难让它运行。

我的计划如下:(a)我想要一个单独的服务,其中包含登录和 getbearertoken 方法(b)该服务在我的 Vue 实例的 beforeCreate() 中初始化,以便我只能在登录后访问该页面(c) get token 方法应该可以从我的项目中的任何其他 .ts 文件中使用,以便我可以将其附加到 post/get 请求中。

到目前为止,我的登录正常,但我正在努力获取令牌:

import { msalConfig, useAuthStore } from '@/stores/auth'
import { PublicClientApplication } from '@azure/msal-browser'

class MsalService {
  msalInstance: PublicClientApplication

  constructor() {
    this.msalInstance = new PublicClientApplication(msalConfig)
    this.initialize()
  }

  async initialize() {
    try {
      await this.msalInstance.initialize()
    } catch (error) {
      console.log('Initialization error', error)
    }
  }

  login() {
    const authStore = useAuthStore()

    this.msalInstance
      .handleRedirectPromise()
      .then((response: any) => {
        if (!response) {
          this.msalInstance.loginRedirect()
        } else {
          authStore.setUser(response.account)
        }
      })
      .catch((error: any) => {
        console.error('Failed to handle redirect:', error)
      })
  }


  async getToken(): Promise<any> {
    try {
      const accounts = this.msalInstance.getAllAccounts()
      if (accounts.length === 0) {
        throw new Error('No accounts found. Please login first.')
      }
      const silentRequest = {
        scopes: [`api://${import.meta.env.VITE_CLIENT_ID}/user_impersonation`],
        account: accounts[0]
      }
      const silentResponse = await this.msalInstance.acquireTokenSilent(silentRequest)
      return silentResponse.accessToken
    } catch (error) {
      console.error('Token acquisition error:', error)
      throw error
    }
  }
}

export const msalService = new MsalService()

在我的 main.ts 中,代码如下所示

import { msalService } from "@/stores/auth"

export const instance = new Vue({
  router,
  ...
  beforeCreate() {

    msalService.initialize().then(() => {
      msalService.login()
    })

  }
}

console.log(await msalService.getToken())

此 getToken() 调用会在控制台中返回“BrowserAuthError:uninitialized_public_client_application:您必须先调用并等待初始化函数,然后再尝试调用任何其他 MSAL API”错误。

如上所述,登录有效,系统要求我输入我的凭据。可能是什么问题?

typescript vuejs2 azure-ad-msal msal
1个回答
0
投票

我尝试使用以下 Vue2 应用程序使用

@azure/msal-browser
包登录并检索访问令牌。我成功登录并检索了访问令牌。

src/services/msalservice.ts:

import { PublicClientApplication, AuthenticationResult } from '@azure/msal-browser';
import { config } from '../Config';

class MsalService {
  private msalInstance: PublicClientApplication;
  private isInitialized: boolean = false;

  constructor() {
    this.msalInstance = new PublicClientApplication({
      auth: {
        clientId: config.appId,
        redirectUri: config.redirectUri,
        authority: config.authority,
      },
      cache: {
        cacheLocation: 'sessionStorage',
        storeAuthStateInCookie: true,
      },
    });
  }

  public async initialize(): Promise<void> {
    try {
      await this.msalInstance.initialize();
      this.isInitialized = true;
      console.log('MSAL instance initialized successfully');
    } catch (error) {
      this.isInitialized = false;
      console.error('Error initializing MSAL instance:', error);
      throw error;  
    }
  }
  private checkInitialization() {
    if (!this.isInitialized) {
      throw new Error("MSAL has not been initialized yet.");
    }
  }

  public getMsalInstance() {
    this.checkInitialization();
    return this.msalInstance;
  }

  public async login(): Promise<AuthenticationResult | null> {
    this.checkInitialization();
    try {
      const loginResponse = await this.msalInstance.loginPopup({
        scopes: config.scopes,
        prompt: 'select_account',
      });
      return loginResponse;
    } catch (error) {
      console.error(error);
      return null;
    }
  }

  public async getAccessToken(): Promise<string | null> {
    this.checkInitialization();
    try {
      const account = this.msalInstance.getAllAccounts()[0];
      if (account) {
        const tokenResponse = await this.msalInstance.acquireTokenSilent({
          scopes: config.scopes,
          account: account,
        });
        return tokenResponse.accessToken;
      }
      return null;
    } catch (error) {
      console.error(error);
      return null;
    }
  }
  
  public logout(): void {
    this.checkInitialization();
    this.msalInstance.logout();
  }
}
export const msalService = new MsalService();

src/components/App.vue:

<template>
    <div id="app">
      <h1>MSAL Vue 2 App</h1>
      <div v-if="!account">
        <button @click="login">Login</button>
      </div>
      <div v-else>
        <p>Welcome, {{ account.name }}</p>
        <p v-if="accessToken">
          <strong>Access Token:</strong>
          <pre>{{ accessToken }}</pre>
        </p>
        <button @click="logout">Logout</button>
      </div>
    </div>
  </template>
  
  <script lang="ts">
  import Vue from 'vue';
  import { msalService } from '../services/msalService';
  
  export default Vue.extend({
    data() {
      return {
        account: null as any,
        accessToken: null as string | null,
        isMsalInitialized: false,
      };
    },
    async mounted() {
      try {
        await msalService.initialize();
        this.isMsalInitialized = true;
        console.log('MSAL instance initialized');
        const msalInstance = msalService.getMsalInstance();
        const accounts = msalInstance.getAllAccounts();
        if (accounts.length > 0) {
          this.account = accounts[0];
          await this.fetchAccessToken();
        }
      } catch (error) {
        console.error('Error initializing MSAL:', error);
      }
    },
    methods: {
      async login() {
        if (!this.isMsalInitialized) {
          console.error('MSAL is not initialized yet.');
          return;
        }
        try {
          const response = await msalService.login();
          if (response) {
            this.account = response.account;
            await this.fetchAccessToken();
          }
        } catch (error) {
          console.error('Login error:', error);
        }
      },
      async fetchAccessToken() {
        try {
          this.accessToken = await msalService.getAccessToken();
        } catch (error) {
          console.error('Error fetching access token:', error);
        }
      },
      logout() {
        msalService.logout();
        this.account = null;
        this.accessToken = null;
      }
    },
  });
  </script>

src/Config.ts:

export const config = {
  appId: '<clientID>',
  redirectUri: 'http://localhost:8080',
  scopes: ['openid', 'profile', 'user.read'],
  authority: 'https://login.microsoftonline.com/<tenantID>',
};

main.ts:

import Vue from 'vue';
import App from './components/App.vue';  

Vue.config.productionTip = false;
new Vue({
  render: (h) => h(App),
}).$mount('#app');

我在单页应用程序下的服务原理的身份验证中添加了以下重定向 URI。

http://localhost:8080

enter image description here

输出:

我成功运行了Vue2项目并在浏览器中得到了以下输出。

enter image description here

我成功登录并检索了访问令牌。

enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.