我有一个Ionic应用程序需要在Azure中进行身份验证,所以我按照本教程安装了MSAL:https://learn.microsoft.com/en-us/graph/tutorials/angular
它的工作原理就像“离子服务”的魅力,但当我在设备中运行它时,当我试图登录Azure时,它就会崩溃。我认为这是因为在Ionic中不允许弹出窗口MSAL显示登录。
因此,我的第一次尝试是更改loginPopup()对loginRedirect()的调用。所以我删除了这个代码:
async signIn(): Promise<void> {
const result = await this.msalService
.loginPopup(OAuthSettings)
.toPromise()
.catch((reason) => {
this.alertsService.addError('Login failed',
JSON.stringify(reason, null, 2));
});
if (result) {
this.msalService.instance.setActiveAccount(result.account);
this.authenticated = true;
this.user = await this.getUser();
}
}我添加了这个新的(基于https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/errors.md):
async signIn(): Promise<void> {
await this.msalService.instance.handleRedirectPromise();
const accounts = this.msalService.instance.getAllAccounts();
if (accounts.length === 0) {
// No user signed in
this.msalService.instance.loginRedirect();
}
}但是这样,用户信息就不会被保存,因为我没有要处理或调用setActiveAccount(结果)的“结果”。它甚至在“离子服务”中也不起作用,所以我放弃了这种方法。
第二种方法是在搜索一个可实现的解决方案两天后,在InAppBrowser (https://ionicframework.com/docs/native/in-app-browser)中显示弹出窗口,因此我将代码更改为:
async signIn(): Promise<void> {
const browser = this.iab.create('https://www.microsoft.com/');
browser.executeScript({ code: "\
const result = await this.msalService\
.loginPopup(OAuthSettings)\
.toPromise()\
.catch((reason) => {\
this.alertsService.addError('Login failed',\
JSON.stringify(reason, null, 2));\
});\
if (result) {\
this.msalService.instance.setActiveAccount(result.account);\
this.authenticated = true;\
this.user = await this.getUser();\
}"
});
}但是它只是打开一个新窗口,没有做更多的事情,它不执行loginPopup(),所以我也放弃了第二个方法。
有人知道如何避免在Ionic中出现弹出问题吗?
谢谢
发布于 2021-12-13 16:08:44
通过使用自定义导航客户端,我设法用cordova-plugin解决了这个问题,下面是我的实现:
CustomNavigationClient
class CustomNavigationClient extends NavigationClient {
async navigateExternal(url: string, options: any) {
// Cortdova implementation
if (window.hasOwnProperty("cordova")) {
var ref = cordova.InAppBrowser.open(url, '_blank', 'location=yes,clearcache=yes,clearsessioncache=yes');
// Check if the appbrowser started a navigation
ref.addEventListener('loadstart', (event: any) => {
// Check if the url contains the #state login parameter
if (event.url.includes('#state')) {
// Close the in app browser and redirect to localhost + the state parameter
// msal-login is a fake route to trigger a page refresh
ref.close();
const domain = event.url.split('#')[0];
const url = event.url.replace(domain, 'http://localhost/msal-login');
window.location.href = url;
}
});
} else {
if (options.noHistory) {
window.location.replace(url);
} else {
window.location.assign(url);
}
}
return true;
}
}app.component.ts
const navigationClient = new CustomNavigationClient();
this.msalService.instance.setNavigationClient(navigationClient);
this.msalService.instance.handleRedirectPromise().then((authResult: any) => {
console.debug('AuthResult ---->', authResult);
if (authResult) {
// your login logic goes here.
} else {
this.msalService.instance.loginRedirect();
}
});发布于 2022-02-12 23:49:21
我可以确认Paolo Cuscelas的解决方案是有效的。我们使用的是离子电容器和cordova InAppBrowser,因为电容器浏览器不支持监听url更改,这是为了“代理”msal路由参数而需要的。
另外,请确保在您的蔚蓝门户中注册重定向uri。
应用程序的其余部分或多或少是基于microsoft提供的msal/角包示例设置的。
电容器CustomNavigationClient
确保将msal交互类型设置为"InteractionType.Redirect“
构造函数要求传入一个InAppBrowser引用。
另外,azure通过#代码而不是#state返回url中的数据,因此请确保相应地拆分url。
class CustomNavigationClient extends NavigationClient {
constructor(private iab: InAppBrowser) {
super();
}
async navigateExternal(url: string, options: any) {
if (Capacitor.isNativePlatform()) {
const browser = this.iab.create(url, '_blank', {
location: 'yes',
clearcache: 'yes',
clearsessioncache: 'yes',
hidenavigationbuttons: 'yes',
hideurlbar: 'yes',
fullscreen: 'yes'
});
browser.on('loadstart').subscribe(event => {
if (event.url.includes('#code')) {
// Close the in app browser and redirect to localhost + the state parameter
browser.close();
const domain = event.url.split('#')[0];
const url = event.url.replace(domain, 'http://localhost/home');
console.log('will redirect to:', url);
window.location.href = url;
}
});
} else {
if (options.noHistory) {
window.location.replace(url);
} else {
window.location.assign(url);
}
}
return true;
}
}app.component.ts
注册导航客户端
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { InAppBrowser } from '@awesome-cordova-plugins/in-app-browser/ngx';
import { MsalBroadcastService, MsalService } from '@azure/msal-angular';
import { AuthenticationResult, EventMessage, EventType, NavigationClient } from '@azure/msal-browser';
import { Capacitor } from '@capacitor/core';
import { Subject } from 'rxjs';
import { filter, tap } from 'rxjs/operators';
import { AzureAuthService } from '@core/auth';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
constructor(
private azureAuthService: AzureAuthService,
private authService: MsalService,
private msalBroadcastService: MsalBroadcastService,
private router: Router,
private iab: InAppBrowser,
private msalService: MsalService,
) {
this.msalService.instance.setNavigationClient(new CustomNavigationClient(this.iab));
}
ngOnInit(): void {
this.msalBroadcastService.msalSubject$
.pipe(
filter((msg: EventMessage) => msg.eventType === EventType.LOGIN_SUCCESS),
)
.subscribe((result: EventMessage) => {
console.log('--> login success 1: ', result);
const payload = result.payload as AuthenticationResult;
this.authService.instance.setActiveAccount(payload.account);
// custom service to handle authentication result within application
this.azureAuthService.handleAuthentication(payload)
.pipe(
tap(() => {
console.log('--> login success 2: ');
this.router.navigate(['/home']);
})
)
.subscribe();
});
}
}package.json
如果使用angulars方法,请确保将依赖项放置在项目特定的package.json文件中,否则,当同步插件(cordova和电容器)与npx上限同步时,插件将被忽略。会导致"...plugin_not_installed“错误。
"dependencies": {
...
"@capacitor/android": "3.4.1",
"cordova-plugin-inappbrowser": "^5.0.0",
"@awesome-cordova-plugins/in-app-browser": "^5.39.1",
"@azure/msal-angular": "^2.0.1",
"@azure/msal-browser": "^2.15.0",
...
}发布于 2022-09-15 10:45:43
我确认Jazjef解决方案可以在Ionic 6上使用电容解决安卓工作白白问题,但IOS需要更改event.url.replace代码以使用电容://localhost/重定向到应用程序,如果让'http://localhost/‘在系统浏览器上打开url,
async navigateExternal(url: string, options: any) {
// Cortdova implementation
if (Capacitor.isNativePlatform()) {
var browser = this.iab.create(url, '_blank', 'location=yes,clearcache=yes,clearsessioncache=yes,hidenavigationbuttons=true,hideurlbar=true,fullscreen=true');
browser.on('loadstart').subscribe(event => {
if (event.url.includes('#code')) {
browser.close();
const domain = event.url.split('#')[0];
const url = event.url.replace(domain, 'capacitor://localhost/home');
window.location.href = url;
}
});
} else {
if (options.noHistory) {
// window.location.replace(url);
} else {
// window.location.assign(url);
}
}
return true;}
https://stackoverflow.com/questions/69391322
复制相似问题