问题
I am creating an $auth
plugin that works fine from the component using this.$auth
main.js
import { Auth0Plugin } from "./auth";
Vue.use(Auth0Plugin, {
domain: process.env.VUE_APP_AUTH0_DOMAIN,
clientId: process.env.VUE_APP_AUTH0_CLIENT_ID,
audience: process.env.VUE_APP_AUTH0_AUDIENCE,
onRedirectCallback: () => {
router.push("/signed-in");
}
});
auth/index.js
import Vue from "vue";
import createAuth0Client from "@auth0/auth0-spa-js";
/** Define a default action to perform after authentication */
const DEFAULT_REDIRECT_CALLBACK = () =>
window.history.replaceState({}, document.title, window.location.pathname);
let instance;
/** Returns the current instance of the SDK */
export const getInstance = () => instance;
/** Creates an instance of the Auth0 SDK. If one has already been created, it returns that instance */
export const useAuth0 = ({
onRedirectCallback = DEFAULT_REDIRECT_CALLBACK,
redirectUri = window.location.origin,
...options
}) => {
if (instance) return instance;
// The 'instance' is simply a Vue object
instance = new Vue({
data() {
return {
loading: true,
isAuthenticated: false,
user: {},
auth0Client: null,
popupOpen: false,
error: null
};
},
methods: {
/** Returns the access token. If the token is invalid or missing, a new one is retrieved */
getTokenSilently(o) {
return this.auth0Client.getTokenSilently(o);
},
},
/** Use this lifecycle method to instantiate the SDK client */
async created() {
// Create a new instance of the SDK client using members of the given options object
this.auth0Client = await createAuth0Client({
domain: options.domain,
client_id: options.clientId,
audience: options.audience,
redirect_uri: redirectUri
});
try {
// If the user is returning to the app after authentication..
if (
window.location.search.includes("code=") &&
window.location.search.includes("state=")
) {
// handle the redirect and retrieve tokens
const { appState } = await this.auth0Client.handleRedirectCallback();
// Notify subscribers that the redirect callback has happened, passing the appState
// (useful for retrieving any pre-authentication state)
onRedirectCallback(appState);
}
} catch (e) {
this.error = e;
} finally {
// Initialize our internal authentication state
this.isAuthenticated = await this.auth0Client.isAuthenticated();
this.user = await this.auth0Client.getUser();
this.loading = false;
}
}
});
return instance;
};
// Create a simple Vue plugin to expose the wrapper object throughout the application
export const Auth0Plugin = {
install(Vue, options) {
Vue.prototype.$auth = useAuth0(options);
}
};
I have a service class that calls an api.
I need to get the api token from this plugin $auth.getTokenSilently()
.
How do I call the instantiated plugin from my api-service.js
file?
I know the below code doesn't work. But it's just to demonstrate what I'm trying to do. utils/api-service.js
export default {
init() {
this.lqdApi = axios.create({
baseURL: process.env.lqdApiBaseUrl,
headers: { Authorization: `Bearer ${$auth.getTokenSilently()}` }
});
return this;
},
}
回答1:
The service should be initialized inside Vue. It can just be injected with initialization data:
init(token) {
this.lqdApi = axios.create({
baseURL: process.env.lqdApiBaseUrl,
headers: { Authorization: `Bearer ${token}` }
});
return this;
},
The problem here is that async created
is a potential antipattern, it doesn't prevent child components from being initialized when auth0Client
and therefore api-service
aren't ready but used by components. If this is the case, one of possible solutions is to make Axios instance available on Vue prototype, like shown here. The instance needs to be created immediately, but a token can be provided to it asynchronously with interceptors because they support promises.
It can be written as a plugin and become available on Vue instance like $auth
:
install(Vue, options) {
Vue.prototype.$axios = axios.create();
},
created() {
if (this.$root === this) {
this.$axios.interceptors.request.use(async config => {
let auth0Client = await this.auth0ClientPromise;
config.headers.Authorization = `Bearer ${auth0Client.getTokenSilently()}`;
return config;
}
}
And a promise of Auth0 client instance should be available on Vue instance in order to be chained by Axios (and probably other things that may depend on it):
this.auth0ClientPromise = createAuth0Client(...);
this.auth0Client = await auth0ClientPromise;
来源:https://stackoverflow.com/questions/60710877/use-vue-js-plugin-in-js-service-module