- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试在我的 ionic(4) cordova 应用程序中使用 Keycloak-js(来自 4.4.0.Final)库。我关注了example和来自 documentation 的说明.我已经安装了cordova-plugin-browsertab
, cordova-plugin-deeplinks
, cordova-plugin-inappbrowser
.已添加 <preference name="AndroidLaunchMode" value="singleTask" />
在我的 config.xml
这就是我对 config.xml 的修改方式。
<widget id="org.phidatalab.radar_armt"....>
<plugin name="cordova-plugin-browsertab" spec="0.2.0" />
<plugin name="cordova-plugin-inappbrowser" spec="3.0.0" />
<plugin name="cordova-plugin-deeplinks" spec="1.1.0" />
<preference name="AndroidLaunchMode" value="singleTask" />
<allow-intent href="http://*/*" />
<allow-intent href="https://*/*" />
<universal-links>
<host name="keycloak-cordova-example.exampledomain.net" scheme="https">
<path event="keycloak" url="/login" />
</host>
</universal-links>
</widget>
我的服务使用 Keycloak-js
如下所示。
static init(): Promise<any> {
// Create a new Keycloak Client Instance
let keycloakAuth: any = new Keycloak({
url: 'https://exampledomain.net/auth/',
realm: 'mighealth',
clientId: 'armt',
});
return new Promise((resolve, reject) => {
keycloakAuth.init({
onLoad: 'login-required',
adapter: 'cordova-native',
responseMode: 'query',
redirectUri: 'android-app://org.phidatalab.radar_armt/https/keycloak-cordova-example.github.io/login'
}).success(() => {
console.log("Success")
resolve();
}).error((err) => {
reject(err);
});
});
}
我可以为 Android
成功构建和运行应用程序.但是,它不起作用。来自 adb
我得到的日志(对于 cordova
和 cordova-native
适配器)
12-04 19:07:35.911 32578-32578/org.phidatalab.radar_armt D/SystemWebChromeClient: ng:///AuthModule/EnrolmentPageComponent.ngfactory.js: Line 457 : ERROR
12-04 19:07:35.911 32578-32578/org.phidatalab.radar_armt I/chromium: [INFO:CONSOLE(457)] "ERROR", source: ng:///AuthModule/EnrolmentPageComponent.ngfactory.js (457)
12-04 19:07:35.918 32578-32578/org.phidatalab.radar_armt D/SystemWebChromeClient: ng:///AuthModule/EnrolmentPageComponent.ngfactory.js: Line 457 : ERROR CONTEXT
12-04 19:07:35.919 32578-32578/org.phidatalab.radar_armt I/chromium: [INFO:CONSOLE(457)] "ERROR CONTEXT", source: ng:///AuthModule/EnrolmentPageComponent.ngfactory.js (457)
如果我尝试在浏览器上运行它,我会得到 "universalLink is undefined"
.
我真的很想得到一些帮助来让它工作。我错过了什么?非常感谢任何形式的帮助。或者是否有解决方法/示例让 keycloak 为 ionic (公共(public))客户端工作?
最佳答案
我在这里发布我的解决方案,因为我浪费了很多时间来获取适用于我的环境的可用插件。 keycloak-js
提供的实现相当过时。因此,如果您尝试将它用于 ionic-3 应用程序,它就是行不通的。
我的解决方案是使用 InAppBrowser
插件(类似于 keycloak-js
的 cordova
方法)并遵循标准 Oauth2 authorization_code
程序。我查看了 keycloak-js
的代码并基于它实现了解决方案。也感谢 keycloak-js
。
在这里。第一步:安装[cordova-inapp-browser][1]
。
第 2 步:示例 keycloak-auth.service.ts
如下所示。这可能会取代 keycloak-js,但仅限于 cordova
选项。
import 'rxjs/add/operator/toPromise'
import {HttpClient, HttpHeaders, HttpParams} from '@angular/common/http'
import {Injectable} from '@angular/core'
import {JwtHelperService} from '@auth0/angular-jwt'
import {StorageService} from '../../../core/services/storage.service'
import {StorageKeys} from '../../../shared/enums/storage'
import {InAppBrowser, InAppBrowserOptions} from '@ionic-native/in-app-browser';
const uuidv4 = require('uuid/v4');
@Injectable()
export class AuthService {
URI_base: 'https://my-server-location/auth';
keycloakConfig: any;
constructor(
public http: HttpClient,
public storage: StorageService,
private jwtHelper: JwtHelperService,
private inAppBrowser: InAppBrowser,
) {
this.keycloakConfig = {
authServerUrl: 'https://my-server-location/auth/', //keycloak-url
realm: 'myrealmmName', //realm-id
clientId: 'clientId', // client-id
redirectUri: 'http://my-demo-app/callback/', //callback-url registered for client.
// This can be anything, but should be a valid URL
};
}
public keycloakLogin(login: boolean): Promise<any> {
return new Promise((resolve, reject) => {
const url = this.createLoginUrl(this.keycloakConfig, login);
const options: InAppBrowserOptions = {
zoom: 'no',
location: 'no',
clearsessioncache: 'yes',
clearcache: 'yes'
}
const browser = this.inAppBrowser.create(url, '_blank', options);
const listener = browser.on('loadstart').subscribe((event: any) => {
const callback = encodeURI(event.url);
//Check the redirect uri
if (callback.indexOf(this.keycloakConfig.redirectUri) > -1) {
listener.unsubscribe();
browser.close();
const code = this.parseUrlParamsToObject(event.url);
this.getAccessToken(this.keycloakConfig, code).then(
() => {
const token = this.storage.get(StorageKeys.OAUTH_TOKENS);
resolve(token);
},
() => reject("Count not login in to keycloak")
);
}
});
});
}
parseUrlParamsToObject(url: any) {
const hashes = url.slice(url.indexOf('?') + 1).split('&');
return hashes.reduce((params, hash) => {
const [key, val] = hash.split('=');
return Object.assign(params, {[key]: decodeURIComponent(val)})
}, {});
}
createLoginUrl(keycloakConfig: any, isLogin: boolean) {
const state = uuidv4();
const nonce = uuidv4();
const responseMode = 'query';
const responseType = 'code';
const scope = 'openid';
return this.getUrlForAction(keycloakConfig, isLogin) +
'?client_id=' + encodeURIComponent(keycloakConfig.clientId) +
'&state=' + encodeURIComponent(state) +
'&redirect_uri=' + encodeURIComponent(keycloakConfig.redirectUri) +
'&response_mode=' + encodeURIComponent(responseMode) +
'&response_type=' + encodeURIComponent(responseType) +
'&scope=' + encodeURIComponent(scope) +
'&nonce=' + encodeURIComponent(nonce);
}
getUrlForAction(keycloakConfig: any, isLogin: boolean) {
return isLogin ? this.getRealmUrl(keycloakConfig) + '/protocol/openid-connect/auth'
: this.getRealmUrl(keycloakConfig) + '/protocol/openid-connect/registrations';
}
loadUserInfo() {
return this.storage.get(StorageKeys.OAUTH_TOKENS).then( tokens => {
const url = this.getRealmUrl(this.keycloakConfig) + '/protocol/openid-connect/userinfo';
const headers = this.getAccessHeaders(tokens.access_token, 'application/json');
return this.http.get(url, {headers: headers}).toPromise();
})
}
getAccessToken(kc: any, authorizationResponse: any) {
const URI = this.getTokenUrl();
const body = this.getAccessTokenParams(authorizationResponse.code, kc.clientId, kc.redirectUri);
const headers = this.getTokenRequestHeaders();
return this.createPostRequest(URI, body, {
header: headers,
}).then((newTokens: any) => {
newTokens.iat = (new Date().getTime() / 1000) - 10; // reduce 10 sec to for delay
this.storage.set(StorageKeys.OAUTH_TOKENS, newTokens);
});
}
refresh() {
return this.storage.get(StorageKeys.OAUTH_TOKENS)
.then(tokens => {
const decoded = this.jwtHelper.decodeToken(tokens.access_token)
if (decoded.iat + tokens.expires_in < (new Date().getTime() /1000)) {
const URI = this.getTokenUrl();
const headers = this.getTokenRequestHeaders();
const body = this.getRefreshParams(tokens.refresh_token, this.keycloakConfig.clientId);
return this.createPostRequest(URI, body, {
headers: headers
})
} else {
return tokens
}
})
.then(newTokens => {
newTokens.iat = (new Date().getTime() / 1000) - 10;
return this.storage.set(StorageKeys.OAUTH_TOKENS, newTokens)
})
.catch((reason) => console.log(reason))
}
createPostRequest(uri, body, headers) {
return this.http.post(uri, body, headers).toPromise()
}
getAccessHeaders(accessToken, contentType) {
return new HttpHeaders()
.set('Authorization', 'Bearer ' + accessToken)
.set('Content-Type', contentType);
}
getRefreshParams(refreshToken, clientId) {
return new HttpParams()
.set('grant_type', 'refresh_token')
.set('refresh_token', refreshToken)
.set('client_id', encodeURIComponent(clientId))
}
getAccessTokenParams(code , clientId, redirectUrl) {
return new HttpParams()
.set('grant_type', 'authorization_code')
.set('code', code)
.set('client_id', encodeURIComponent(clientId))
.set('redirect_uri', redirectUrl);
}
getTokenUrl() {
return this.getRealmUrl(this.keycloakConfig) + '/protocol/openid-connect/token';
}
getTokenRequestHeaders() {
const headers = new HttpHeaders()
.set('Content-Type', 'application/x-www-form-urlencoded');
const clientSecret = (this.keycloakConfig.credentials || {}).secret;
if (this.keycloakConfig.clientId && clientSecret) {
headers.set('Authorization', 'Basic ' + btoa(this.keycloakConfig.clientId + ':' + clientSecret));
}
return headers;
}
getRealmUrl(kc: any) {
if (kc && kc.authServerUrl) {
if (kc.authServerUrl.charAt(kc.authServerUrl.length - 1) == '/') {
return kc.authServerUrl + 'realms/' + encodeURIComponent(kc.realm);
} else {
return kc.authServerUrl + '/realms/' + encodeURIComponent(kc.realm);
}
} else {
return undefined;
}
}
}
第 3 步:然后您可以根据需要在您的组件中使用此服务。
@Component({
selector: 'page-enrolment',
templateUrl: 'enrolment-page.component.html'
})
export class EnrolmentPageComponent {
constructor(
public storage: StorageService,
private authService: AuthService,
) {}
goToRegistration() {
this.loading = true;
this.authService.keycloakLogin(false)
.then(() => {
return this.authService.retrieveUserInformation(this.language)
});
}
}
注意:keycloakLogin(true)带你到登录页面或keycloakLogin(false)带你到keycloak的注册页面。
我希望这能或多或少地帮助你解决它。
关于android - ionic 应用程序的Keycloak : keycloak-js with cordova-native does not work,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53630761/
我已将 Keycloak 设置为 SAML 代理,身份验证由当局提供的外部 IdP 完成。使用此 IdP 登录的用户都被接受,我们需要从 Keycloak 获得一个 OAuth token 来访问我们
我在 master 有一个服务帐号领域。来自 admin-cli我要分配服务帐号master-realm-client管理员角色。我怎样才能做到这一点。 kcadm.sh add-roles -r m
在 Keycloak 中,是否可以对同一领域中的所有客户端仅进行一次登录?我已经以这种方式配置了服务器(从管理控制台): - 创建一个新领域(我们称之为 MyRealm); - 创建两个不同的客户端(
我们的团队正在开发一个集成到 Keycloak 中的项目。我们创建了一个自定义领域,例如 ProjectX ,并使其上的自定义主题能够应用于 Keycloak 的登录页面。 由于我们的主题应用于领域
Keycloak 是一个很棒的工具,但它缺乏适当的文档。 所以我们有 Realm.roles、Client.roles 和 User.roles 使用特定客户端访问应用程序时,这 3 者如何协同工作?
我们的团队正在开发一个集成到 Keycloak 中的项目。我们创建了一个自定义领域,例如 ProjectX ,并使其上的自定义主题能够应用于 Keycloak 的登录页面。 由于我们的主题应用于领域
有没有办法让所有用户在 keycloak 中创建自定义用户属性(如电话号码)? 最佳答案 您可以创建一个组并向其添加一个属性。 然后将该组设置为默认组。这样,所有用户都可以使用设置为组的属性 关于ke
我还尝试了 Web 来源和有效重定向 URI 的所有不同组合 我通过 keycloak 登录,它不断地在我的本地主机应用程序和这个 url 之间来回重定向我:http://localhost:4200
在 Keycloak's documentation ,据说为了部署提供程序,我可以 copy your provider jar to the Keycloak deploy/ directory,
目前,我使用此端点一次将用户添加到一个组: PUT /{realm}/users/{id}/groups/{groupId} 在我的用例中,批量执行影响是有益的,到目前为止我还没有找到这样做的记录方式
目前,我使用此端点一次将用户添加到一个组: PUT /{realm}/users/{id}/groups/{groupId} 在我的用例中,批量执行影响是有益的,到目前为止我还没有找到这样做的记录方式
我一直在尝试在 docker-compose 文件中使用 jboss/keycloak-mysql 来建立 Keycloak 服务器和 mysql 数据库。我在本地部署期间遇到一个问题,告诉我 WEB
我正在使用 Tomcat 适配器运行 Keycloak。但是,当我尝试获取 KeycloakPrincipal 时,它出错了; java.lang.ClassCastException: org.ke
我正在使用 keycloak 4.5.0 v 并创建了一个领域。我已经设置了登录以启用忘记用户名和验证电子邮件。在我输入的电子邮件选项卡中 host - smtp.gmail.com smtp po
我想让我的客户端应用程序从 keycloak 访问用户信息。因此,我在 keycloak 中创建了另一个领域 (myrealm1),并在该领域内创建了一个新客户端 (myclient1)。 key 斗
正如我在此链接中看到的 https://www.keycloak.org/docs/latest/authorization_services/#_overview ,客户端中应该有一个授权选项卡,如
这些 keycloak 端点有什么用? issuer: "http://localhost:8180/auth/realms/dev", authorization_endpoint: "http:/
我们需要将数百个用户从 csv 文件导入 Keycloak。我还没有找到任何现成的导入功能来做到这一点。 有没有人做过任何导入程序或至少有一些框架来构建? REST API 可能是唯一的方法 - 或者
我已经使用 LDAP 用户联盟配置了 Keycloak。当用户想要登录应用程序时,他会被重定向到 Keycloak 登录页面,输入 uid/pwd 并使用 LDAP 绑定(bind)进行身份验证。 这
有没有人在 Keycloak 中使用过 SCIM?如果是这样,你能指出我的文档吗?我用谷歌搜索过,它似乎不是受支持的配置。 最佳答案 不幸的是,Keycloak 尚不支持 SCIM。他们的 Jira
我是一名优秀的程序员,十分优秀!