node.js - node - vue js sqlite
¿Cómo se autentica una aplicación VueJS con Azure AD? (2)
Estoy configurando una aplicación utilizando el marco VueJS 2.x y necesita autenticar a los usuarios a través del servicio Azure Active Directory. Ya tengo "información de inicio de sesión" (URL de autenticación y de token) necesaria para el servicio.
Hasta ahora, solo he encontrado un artículo que muestra la configuración en VueJS, pero se basa en un servicio de terceros (Auth0), lo que agrega convolución innecesaria en el proceso.
¿Cómo se procede cuando no hay ningún módulo VUEJS npm que permita autenticarse fácilmente? ¿O tienes que confiar en una biblioteca fuera de Vue como Adal JS ?
Cualquier sugerencia sería útil.
El concepto de proteger los datos en el cliente es siempre verificar la información de autenticación cuando es necesario.
No estoy seguro de que haya una biblioteca para ayudar a la seguridad de la aplicación VueJs. Sin embargo, podemos aprovechar fácilmente los Adal js para la autenticación.
También escribí una demostración simple para su referencia:
Index.html :
<html>
<head>
<script src="https://unpkg.com/vue"></script>
<script src="node_modules/adal-angular/lib/adal.js"> </script>
<script src="config.js"> </script>
<script>
var authContext=new AuthenticationContext(config);
function login(){
authContext.login();
}
function init(configOptions){
if (configOptions) {
// redirect and logout_redirect are set to current location by default
var existingHash = window.location.hash;
var pathDefault = window.location.href;
if (existingHash) {
pathDefault = pathDefault.replace(existingHash, '''');
}
configOptions.redirectUri = configOptions.redirectUri || pathDefault;
configOptions.postLogoutRedirectUri = configOptions.postLogoutRedirectUri || pathDefault;
// create instance with given config
} else {
throw new Error(''You must set configOptions, when calling init'');
}
// loginresource is used to set authenticated status
updateDataFromCache(authContext.config.loginResource);
}
var _oauthData = { isAuthenticated: false, userName: '''', loginError: '''', profile: '''' };
var updateDataFromCache = function (resource) {
// only cache lookup here to not interrupt with events
var token = authContext.getCachedToken(resource);
_oauthData.isAuthenticated = token !== null && token.length > 0;
var user = authContext.getCachedUser() || { userName: '''' };
_oauthData.userName = user.userName;
_oauthData.profile = user.profile;
_oauthData.loginError = authContext.getLoginError();
};
function saveTokenFromHash(){
var hash = window.location.hash;
var requestInfo = authContext.getRequestInfo(hash);
if (authContext.isCallback(hash)) {
// callback can come from login or iframe request
var requestInfo = authContext.getRequestInfo(hash);
authContext.saveTokenFromHash(requestInfo);
window.location.hash = '''';
if (requestInfo.requestType !== authContext.REQUEST_TYPE.LOGIN) {
authContext.callback = window.parent.AuthenticationContext().callback;
}
}
}
function isAuthenticate(){
return _oauthData.isAuthenticated;
}
saveTokenFromHash();
init(config);
</script>
</head>
<body>
<div id="app">
<p v-if="_oauthData.isAuthenticated">Hello {{oauthData.userName}}</p>
<button onclick="login()" v-else>Login</button>
</div>
<script>
var app=new Vue({
el: ''#app'',
data: {
oauthData:_oauthData,
}
})
</script>
</body>
</html>
config.js :
var config = {
tenant: ''xxx.onmicrosoft.com'',
clientId: '''',
redirectUri: '''',
cacheLocation: ''localStorage''
};
Para resolver este problema, me apoyé en ADAL JS . He hecho una aplicación de muestra Vue + Vue-Router disponible aquí , pero incluiré las piezas importantes a continuación.
En tu paquete .json:
"dependencies": {
"adal-angular": "^1.0.15",
"vue": "^2.5.2",
"vue-router": "^3.0.1"
},
Un módulo contenedor básico para la biblioteca ADAL JS:
import AuthenticationContext from ''adal-angular/lib/adal.js''
const config = {
tenant: ''your aad tenant'',
clientId: ''your aad application client id'',
redirectUri: ''base uri for this application'',
cacheLocation: ''localStorage''
};
export default {
authenticationContext: null,
userProfilePromise: null,
/**
* @return {Promise}
*/
initialize() {
this.authenticationContext = new AuthenticationContext(config);
return new Promise((resolve, reject) => {
if (this.authenticationContext.isCallback(window.location.hash) || window !== window.parent) {
// redirect to the location specified in the url params.
this.authenticationContext.handleWindowCallback();
} else {
var user = this.authenticationContext.getCachedUser();
if (user && window.parent === window && !window.opener) {
// great, we have a user.
} else {
// no user, kick off the sign in flow.
this.signIn();
}
resolve();
}
});
},
/**
* @return {Promise.<String>} A promise that resolves to an ADAL token for resource access
*/
acquireToken() {
return new Promise((resolve, reject) => {
this.authenticationContext.acquireToken(''<azure active directory resource id>'', (error, token) => {
if (error || !token) {
return reject(error);
} else {
return resolve(token);
}
});
});
},
/**
* Issue an interactive authentication request for the current user and the api resource.
*/
acquireTokenRedirect() {
this.authenticationContext.acquireTokenRedirect(''<azure active directory resource id>'');
},
/**
* @return {Boolean} Indicates if there is a valid, non-expired access token present in localStorage.
*/
isAuthenticated() {
// getCachedToken will only return a valid, non-expired token.
if (this.authenticationContext.getCachedToken(config.clientId)) { return true; }
return false;
},
/**
* @return {Promise.<Object>} An ADAL user profile object.
*/
getUserProfile() {
if (!this.userProfilePromise) {
this.userProfilePromise = this.initialize().then(() => {
return this.authenticationContext.getCachedUser().profile;
});
}
return this.userProfilePromise;
},
signIn() {
this.authenticationContext.login();
},
signOut() {
this.authenticationContext.logOut();
}
}
En el punto de entrada de la aplicación (main.js si usaste vue-cli):
import Vue from ''vue''
import App from ''./App''
import router from ''./router''
import authentication from ''./authentication''
// Init adal authentication - then create Vue app.
authentication.initialize().then(_ => {
/* eslint-disable no-new */
new Vue({
el: ''#app'',
router,
template: ''<App/>'',
components: { App }
});
});
Para su configuración de enrutador Vue:
import Vue from ''vue''
import Router from ''vue-router''
import HelloWorld from ''@/components/HelloWorld''
import authentication from ''../authentication''
Vue.use(Router)
const router = new Router({
mode: ''history'',
routes: [
{
path: ''/'',
name: ''HelloWorld'',
component: HelloWorld,
meta: {
requiresAuthentication: true
}
}
]
})
// Global route guard
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuthentication)) {
// this route requires auth, check if logged in
if (authentication.isAuthenticated()) {
// only proceed if authenticated.
next();
} else {
authentication.signIn();
}
} else {
next();
}
});
export default router;
En sus componentes Vue:
import authentication from ''./authentication''
...
computed: {
isAuthenticated() {
return authentication.isAuthenticated();
}
},
methods: {
logOut() {
authentication.signOut();
}
}
Agregar token de acceso para solicitar encabezados
El siguiente es un ejemplo de un interceptor HTTP vue-resource, pero cualquier método servirá.
Vue.http.interceptors.push(function (request, next) {
auth.acquireToken().then(token => {
// Set default request headers for every request
request.headers.set(''Content-Type'', ''application/json'');
request.headers.set(''Ocp-Apim-Subscription-Key'', ''api key'');
request.headers.set(''Authorization'', ''Bearer '' + token)
// continue to next interceptor
next();
});
});
Espero que esto le ahorre a alguien un poco de tiempo :)