vpu-auth.js 7.98 KiB
import {i18n} from './i18n.js';
import {html, LitElement} from 'lit-element';
import JSONLD from 'vpu-common/jsonld'
import utils from "./utils";
/**
* Keycloak auth web component
* https://www.keycloak.org/docs/latest/securing_apps/index.html#_javascript_adapter
*
* Dispatches an event `vpu-auth-init` and sets some global variables:
* window.VPUAuthSubject: Keycloak username
* window.VPUAuthToken: Keycloak token to send with your requests
* window.VPUUserFullName: Full name of the user
* window.VPUPersonId: Person identifier of the user
* window.VPUPerson: Person json object of the user (optional, enable by setting the `load-person` attribute,
* which will dispatch a `vpu-auth-person-init` event when loaded)
*/
class VPUAuth extends LitElement {
constructor() {
super();
this.lang = 'de';
this.forceLogin = false;
this.loadPerson = false;
this.clientId = "";
this.keyCloakInitCalled = false;
this._keycloak = null;
this.token = "";
this.subject = "";
this.name = "";
this.personId = "";
// Create the events
this.initEvent = new CustomEvent("vpu-auth-init", { "detail": "KeyCloak init event" });
this.personInitEvent = new CustomEvent("vpu-auth-person-init", { "detail": "KeyCloak person init event" });
this.keycloakDataUpdateEvent = new CustomEvent("vpu-auth-keycloak-data-update", { "detail": "KeyCloak data was updated" });
}
/**
* See: https://lit-element.polymer-project.org/guide/properties#initialize
*/
static get properties() {
return {
lang: { type: String },
forceLogin: { type: Boolean, attribute: 'force-login' },
loadPerson: { type: Boolean, attribute: 'load-person' },
clientId: { type: String, attribute: 'client-id' },
name: { type: String, attribute: false },
token: { type: String, attribute: false },
subject: { type: String, attribute: false },
personId: { type: String, attribute: false },
keycloak: { type: Object, attribute: false },
};
}
connectedCallback() {
super.connectedCallback();
i18n.changeLanguage(this.lang);
const href = window.location.href;
// load Keycloak if we want to force the login or if we were redirected from the Keycloak login page
if (this.forceLogin || (href.indexOf('#state=') > 0 && href.indexOf('&session_state=') > 0)) {
this.loadKeyCloak();
}
this.updateComplete.then(()=>{
});
}
loadKeyCloak() {
const that = this;
console.log("loadKeyCloak");
if (!this.keyCloakInitCalled) {
// inject Keycloak javascript file
const script = document.createElement('script');
script.type = 'text/javascript';
script.async = true;
script.onload = function () {
that.keyCloakInitCalled = true;
that._keycloak = Keycloak({
url: 'https://auth-dev.tugraz.at/auth',
realm: 'tugraz',
clientId: that.clientId,
});
// See: https://www.keycloak.org/docs/latest/securing_apps/index.html#_javascript_adapter
that._keycloak.init({onLoad: 'login-required'}).success(function (authenticated) {
console.log(authenticated ? 'authenticated' : 'not authenticated!');
console.log(that._keycloak);
that.setStateToLogin(true);
that.updateKeycloakData();
that.dispatchInitEvent();
if (that.loadPerson) {
JSONLD.initialize(utils.getAPiUrl(), (jsonld) => {
// find the correct api url for the current person
// we are fetching the logged-in person directly to respect the REST philosophy
// see: https://github.com/api-platform/api-platform/issues/337
const apiUrl = jsonld.getApiUrlForEntityName("Person") + '/' + that.personId;
fetch(apiUrl, {
headers: {
'Content-Type': 'application/ld+json',
'Authorization': 'Bearer ' + that.token,
},
})
.then(response => response.json())
.then((person) => {
window.VPUPerson = person;
that.dispatchPersonInitEvent();
});
});
}
}).error(function () {
console.log('Failed to initialize');
});
// auto-refresh token
that._keycloak.onTokenExpired = function() {
that._keycloak.updateToken(5).success(function(refreshed) {
if (refreshed) {
console.log('Token was successfully refreshed');
that.updateKeycloakData();
} else {
console.log('Token is still valid');
}
}).error(function() {
console.log('Failed to refresh the token, or the session has expired');
});
}
};
// https://www.keycloak.org/docs/latest/securing_apps/index.html#_javascript_a
script.src = '//auth-dev.tugraz.at/auth/js/keycloak.js';
//Append it to the document header
document.head.appendChild(script);
}
}
login(e) {
this.loadKeyCloak();
}
logout(e) {
this._keycloak.logout();
}
/**
* Dispatches the init event
*/
dispatchInitEvent() {
this.setStateToLogin(false);
document.dispatchEvent(this.initEvent);
}
setStateToLogin(state) {
this.shadowRoot.querySelector('#login-block').style.display = state ? "flex" : "none";
this.shadowRoot.querySelector('#logout-block').style.display = state ? "none" : "flex";
}
/**
* Dispatches the person init event
*/
dispatchPersonInitEvent() {
document.dispatchEvent(this.personInitEvent);
}
/**
* Dispatches the keycloak data update event
*/
dispatchKeycloakDataUpdateEvent() {
document.dispatchEvent(this.keycloakDataUpdateEvent);
}
updateKeycloakData() {
this.name = this._keycloak.idTokenParsed.name;
this.token = this._keycloak.token;
this.subject = this._keycloak.subject;
this.personId = this._keycloak.idTokenParsed.preferred_username;
window.VPUAuthSubject = this.subject;
window.VPUAuthToken = this.token;
window.VPUUserFullName = this.name;
window.VPUPersonId = this.personId;
console.log("Bearer " + this.token);
this.dispatchKeycloakDataUpdateEvent();
}
render() {
return html`
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.5/css/bulma.min.css">
<style>
#logout-block { display: none }
</style>
<div id="logout-block" class="columns is-vcentered"">
<div class="column">
${this.name}
</div>
<div class="column">
<button @click="${this.logout}" class="button">${i18n.t('logout')}</button>
</div>
</div>
<div id="login-block" class="columns is-vcentered"">
<div class="column">
<button id="login-button" @click="${this.login}" class="button">${i18n.t('login')}</button>
</div>
</div>
`;
}
}
customElements.define('vpu-auth', VPUAuth);