我正在尝试在 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”错误。
如上所述,登录有效,系统要求我输入我的凭据。可能是什么问题?
我尝试使用以下 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
输出:
我成功运行了Vue2项目并在浏览器中得到了以下输出。
我成功登录并检索了访问令牌。