Skip to content

Instantly share code, notes, and snippets.

@zerkalica
Last active August 18, 2023 17:50
Show Gist options
  • Save zerkalica/911562364a870d0515c3bdea10a25c8d to your computer and use it in GitHub Desktop.
Save zerkalica/911562364a870d0515c3bdea10a25c8d to your computer and use it in GitHub Desktop.
keycloak
namespace $ {
export class $gd_rad_session_web extends $gd_rad_session {
client_id() {
return 'pa-admin'
}
@ $mol_mem
token_access(next?: string | null) {
return this.$.$gd_rad_transport.token(next) ?? undefined
}
@ $mol_mem
token_refresh(next?: string | null) {
return this.$.$mol_state_local.value('kc_mol_rt', next) ?? undefined
}
@ $mol_mem
token_idt(next?: string | null) {
return this.$.$mol_state_local.value('kc_mol_idt', next) ?? undefined
}
minValidity() {
return 30
}
@ $mol_mem
// https://www.keycloak.org/docs/latest/securing_apps/index.html#_javascript_adapter
protected kc_raw() {
const oidc = this.oidc()
const clientId = this.client_id()
if (!oidc?.realm || !clientId) throw new Error('No oidc.realm: setup application')
const kc = new $lib_keycloak({
url: oidc.url,
realm: oidc.realm,
clientId,
})
kc.onAuthRefreshSuccess = $mol_wire_async(() => this.success())
kc.onAuthRefreshError = $mol_wire_async(() => this.error())
kc.onTokenExpired = $mol_wire_async(() => this.update())
// kc.destructor = () => kc.clearToken()
return $mol_wire_sync(kc as typeof kc & { didInitialize?: boolean })
}
// При возврате с сайта авторизации, keycloak пихает свои параметры в урл.
// вызов kc.init выпиливает их, т.е. меняет href, который аргумент у kc.init
// Поэтому mol запускает kc.init с нуля и тот падает, т.к. проверяет повторные запуски
// mol_action кэшит href до завершения kc_inited и аргументы kc.init не меняются
@ $mol_action
protected href() {
return this.$.$mol_dom_context.location.href
}
// Задача получить настроенный инстанс keycloak
// Сам инстанс создается в kc_raw и кэшируется, однако у инстанса надо еще вызвать асинхронный метод kc.init
// Хелпер $mol_wire_sync делает этот метод псевдосинхронным
// Т.к. init надо вызовать только один раз, то реактивную связь с token_access и пр. параметрами надо разорвать
// Для этого и нужна связка mol_mem + mol_action
// экшен не дает подписываться на метод из которого вызван, а mem кэшит результат экшена
@ $mol_mem
@ $mol_action
kc() {
const kc = this.kc_raw()
kc.init({
token: this.token_access(),
idToken: this.token_idt(),
refreshToken: this.token_refresh(),
redirectUri: this.href(),
timeSkew: 0,
})
if (kc.authenticated && this.expired()) this.update()
this.success()
return kc
}
@ $mol_action
override update(validity = this.minValidity()) {
return this.kc_raw().updateToken(validity)
}
expired() {
return this.kc_raw().isTokenExpired(this.minValidity())
}
@ $mol_action
success() {
const kc = this.kc_raw()
this.token_access(kc.token)
this.token_refresh(kc.refreshToken)
this.token_idt(kc.idToken)
}
@ $mol_action
clear() {
const place = '$gd_rad_session:clear'
this.$.$mol_log3_come({ message: 'begin update token', place })
const refreshed = this.update(-1)
this.$.$mol_log3_done({ message: 'done update token, refreshed=' + refreshed, place })
}
@ $mol_action
error() {
this.token_access(null)
this.token_refresh(null)
this.token_idt(null)
}
register_url() {
return this.kc().createRegisterUrl({
redirectUri: $mol_dom_context.location.href
})
}
login_url() {
return this.kc().createLoginUrl({
redirectUri: $mol_dom_context.location.href
})
}
override login_start() {
this.$.$mol_dom_context.location.replace(this.login_url())
}
override register() {
this.$.$mol_dom_context.location.replace(this.register_url())
}
override token() {
this.kc()
return this.token_access()
}
}
$.$gd_rad_session = $gd_rad_session_web
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment