Flutter Azure认证插件msal_auth_azure的使用
Flutter Azure认证插件msal_auth_azure的使用
请参考以下详细说明和示例代码,了解如何在Flutter应用中使用msal_auth_azure插件进行Azure认证。
版本 3.0.0
我们已将代码库更新到Dart 3,并更改了iOS刷新令牌处理。我们从原始库分叉并更改了版本号为3.0.0。 原始分支是msal_flutter,但我们目前不使用它。
升级指南
要将旧项目升级到V2,请确保执行以下操作:
- 更新gradle到3.6.0或更高版本。
- 更新Kotlin到1.4.31或更高版本(可能与1.4.0+的较低版本兼容,但未经过测试)。
- 更新
msal_default_config.json
文件以使用此仓库中的最新版本。 - 更新Flutter到最新版本。
版本 1.0.0+ 警告
版本1.0.0使用更新后的MSAL库并迁移到Android-X。1.0.0与旧版本不兼容。请仅在准备迁移您的Android应用并更改构造函数调用方式时才更新到1.0.+。版本1+是使用MSAL在iOS 13+上所必需的。
不建议使用login.microsoftonline.com
作为身份验证服务器和端点,因为旧的身份验证服务器可能会被弃用,并且由于域相同而无法区分保存的密码。
新的身份验证服务器模板为:
https://<tenant>.b2clogin.com/tfp/<tenant>.onmicrosoft.com/<user-flow>
例如:
https://msalfluttertest.b2clogin.com/tfp/msalfluttertest.onmicrosoft.com/B2C_1_sisu
MSAL Wrapper Library for Flutter
请注意,该产品处于非常早期的Alpha发布阶段,可能会有变动和错误。
Microsoft Authentication Library Flutter Wrapper是一个使用MSAL库(适用于Android和iOS)的封装。当前只支持公共客户端应用程序功能,使用隐式工作流。 如果您有其他功能需求,请告知我们。
设置
要在库中使用MSAL Flutter,首先需要设置一个Azure AD B2C租户和移动客户端。详细说明可以在这里找到。
Flutter
在Flutter应用中导入msal_auth_azure
包,将其添加到pubspec.yaml
文件的依赖项列表中:
dependencies:
msal_auth_azure: ^1.0.0+2
Android (Kotlin)
请确保使用Kotlin版本1.4.31或更高版本。要设置这一点,请转到应用的Android文件夹,打开build.gradle
文件,并在buildscript:ext.kotlin_version
下将版本更改为1.4.31或更高版本。
确保AndroidManifest.xml包含互联网权限
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
在AndroidManifest.xml文件中添加意图过滤器
替换<YOUR-CLIENT-ID>
为你Azure B2C应用的客户端ID。
<activity
android:name="com.microsoft.identity.client.BrowserTabActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="msauth"
android:host="YOUR_PACKAGE_NAME"
android:path="/YOUR_BASE64_ENCODED_PACKAGE_SIGNATURE" />
</intent-filter>
</activity>
将msal_default_config.json
复制到应用的android/src/main/res/raw
文件夹
默认情况下,重定向URL为msal<YOUR-CLIENT-ID>://auth
,但如果选择了不同的重定向URL,请输入该URL。注意,重定向URL方案和主机组合必须是唯一的,并且如果更改了它们,也需要在第2步的活动意图过滤器中更改。
警告:不要将应用程序类型设置为单个。MSAL Flutter包装器仅兼容较新的多账户配置。
对于示例,请参见此处。
最低SDK版本必须至少为21
如果从默认版本16的新Flutter应用开始,请在android > app > build.gradle
文件中的android:defaultConfig > minSdkVersion
下更改此设置。
iOS (Swift)
此部分主要复制并修改自官方iOS MSAL库GitHub仓库的步骤1。更多详情请访问该仓库。
在Info.plist文件中添加回调的URL方案
替换<YOUR-CLIENT-ID>
为你Azure B2C应用的客户端ID。
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>msauth.[BUNDLE-ID]</string>
</array>
</dict>
</array>
添加LSApplicationQueriesSchemes
以允许调用Microsoft Authenticator(用于身份验证代理)
<key>LSApplicationQueriesSchemes</key>
<array>
<string>msauthv2</string>
<string>msauthv3</string>
</array>
在Xcode中打开应用的iOS项目,在Runner
应用中展开Keychain Sharing
并添加键链组com.microsoft.adalcache
在AppDelegate.swift中导入MSAL库
import MSAL
在AppDelegate类中添加以下函数
override func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
guard let sourceApplication = options[UIApplication.OpenURLOptionsKey.sourceApplication] as? String else {
return false
}
return MSALPublicClientApplication.handleMSALResponse(url, sourceApplication: sourceApplication)
}
故障排除
可能遇到最低iOS部署过低的错误。MSAL Flutter要求最低iOS版本为11.0。
要设置这一点,请在iOS文件夹根目录下的Podfile文件的第一行添加platform :ios, '11.0'
。
当从MSAL Flutter的旧版本升级时,你可能还需要删除iOS文件夹中的Podfile.lock文件。
如何使用
在Flutter中导入包
import 'package:msal_auth_azure/msal_auth_azure.dart';
使用静态工厂方法创建公共客户端应用程序实例
使用默认权威机构:
var pca = await MSALPublicClientApplication.createPublicClientApplication("YOUR-CLIENT-ID");
指定权威机构:
var pca = await MSALPublicClientApplication.createPublicClientApplication("YOUR-CLIENT-ID", authority: "https://<tenant>.b2clogin.com/tfp/<tenant>.onmicrosoft.com/<user-flow>");
如果权威机构为空,则将使用默认权威机构,由相关的MSAL库实现定义,默认是公共端点。
交互式获取令牌
调用acquireToken
函数传递你希望获取令牌的范围。注意该函数会在失败时抛出异常,并应使用try-catch块包围。
不要包括默认添加的openid
或user_impersonation
范围。
try {
String token = await pca.acquireToken(["https://msalfluttertest.onmicrosoft.com/msalbackend/user_impersonation"]);
} on MsalException {
// 错误处理逻辑
}
静默获取令牌
一旦用户至少登录一次,可以调用acquireTokenSilent
函数,传递你希望获取令牌的范围。注意该函数会在失败时抛出异常,并应使用try-catch块包围。
不要包括默认添加的openid
或user_impersonation
范围。
try {
String token = await pca.acquireTokenSilent(["https://msalfluttertest.onmicrosoft.com/msalbackend/user_impersonation"]);
} on MsalException {
// 错误处理逻辑
}
登出
调用logout
方法。
try {
await pca.logout();
} on MsalException {
// 错误处理逻辑
}
可能抛出的异常列表
异常名称 | 描述 |
---|---|
MsalException | 基础异常,继承于所有其他异常。用于一般或未知错误 |
MsalChangedClientIdException | 尝试初始化第二个具有不同客户端ID的应用程序 |
MsalInitializationException | 初始化客户端时发生错误,最可能是由于配置文件不正确 |
MsalInvalidConfigurationException | 设置公共客户端应用程序时的配置错误,如无效的客户端ID或权威机构 |
MsalInvalidScopeException | 无效的范围或未提供范围。目前仅在Android上受支持 |
MsalNoAccountException | 用户尚未登录,已注销或刷新令牌已过期,无法执行静默获取令牌 |
MsalUninitializedException | 在客户端初始化之前调用了客户端方法 |
MsalUserCancelledException | 用户取消了登录请求。仅在Android上受支持,iOS会抛出MsalException |
故障排除
请注意,目前在使用稍旧版本Kotlin的Android上存在一个问题。
如果你在尝试获取令牌时遇到类似“找不到静态成员msalApp”的错误,请转到应用的Android文件夹,打开build.gradle
文件,并将第二行的Kotlin版本从1.3.10更改为1.3.50。更多详情请查看问题#4。
修复将很快实施。
示例代码
以下是完整的示例代码,展示了如何在Flutter应用中使用msal_auth_azure插件进行Azure认证。
import 'dart:async';
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:msal_auth_azure/msal_auth_azure.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
[@override](/user/override)
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
static const String _authority =
"https://msalfluttertest.b2clogin.com/tfp/3fab2993-1fec-4a8c-a6d8-2bfea01e64ea/B2C_1_phonesisu";
static const String _iosRedirectUri =
"msauth.com.muljin.msalflutterv2://auth";
static const String _androidRedirectUri =
"msauth://uk.co.moodio.msal_flutter_example/TvkGQnk1ERb%2Bl9pB4OeyeWrYmqo%3D";
static const String _clientId = "fc6136e7-43d1-489c-b221-630e9e4402d3";
static const List<String> _scopes = [
"https://msalfluttertest.onmicrosoft.com/msaltesterapi/All"
];
String _output = 'NONE';
final config = MSALPublicClientApplicationConfig(
androidRedirectUri: _androidRedirectUri,
iosRedirectUri: _iosRedirectUri,
clientId: _clientId,
androidConfig: MSALAndroidConfig(
authorities: [Authority(authorityUrl: Uri.parse(_authority))]),
authority: Uri.parse(_authority),
);
MSALPublicClientApplication? pca;
List<MSALAccount>? accounts;
Future<void> _acquireToken() async {
print("called acquiretoken");
// 如果尚未创建PCA,则创建
if (pca == null) {
print("creating pca...");
pca = await MSALPublicClientApplication.createPublicClientApplication(config);
await pca!.initWebViewParams(MSALWebviewParameters());
}
print("pca created");
String res = '';
try {
MSALResult? resp = await pca!.acquireToken(MSALInteractiveTokenParameters(scopes: _scopes));
res = resp?.account.identifier ?? 'noAuth';
} on MsalUserCancelledException {
res = "User cancelled";
} on MsalNoAccountException {
res = "no account";
} on MsalInvalidConfigurationException {
res = "invalid config";
} on MsalInvalidScopeException {
res = "Invalid scope";
} on MsalException {
res = "Error getting token. Unspecified reason";
}
setState(() {
_output = res;
});
}
Future<void> _loadAccount() async {
if (pca == null) {
print("initializing pca");
pca = await MSALPublicClientApplication.createPublicClientApplication(config);
await pca!.initWebViewParams(MSALWebviewParameters());
}
try {
final result = await pca!.loadAccounts();
if (result != null) {
accounts = result;
}
} catch (e) {
log(e.toString());
}
setState(() {});
}
Future<void> _acquireTokenSilently() async {
if (pca == null) {
print("initializing pca");
pca = await MSALPublicClientApplication.createPublicClientApplication(config);
await pca!.initWebViewParams(MSALWebviewParameters());
}
String res = 'res';
try {
final response = await pca!.acquireTokenSilent(
MSALSilentTokenParameters(
scopes: _scopes,
),
accounts?.isEmpty == true ? null : accounts?.first);
res = response?.account.identifier ?? '';
} on MsalUserCancelledException {
res = "User cancelled";
} on MsalNoAccountException {
res = "no account";
} on MsalInvalidConfigurationException {
res = "invalid config";
} on MsalInvalidScopeException {
res = "Invalid scope";
} on MsalException {
res = "Error getting token silently!";
}
print("Got token");
print(res);
setState(() {
_output = res;
});
}
Future _logout() async {
print("called logout");
if (pca == null) {
print("initializing pca");
pca = await MSALPublicClientApplication.createPublicClientApplication(config);
await pca!.initWebViewParams(MSALWebviewParameters());
}
print("pca is not null");
String res;
try {
if (accounts?.isNotEmpty == true) {
await pca!.logout(MSALSignoutParameters(), accounts!.first);
}
res = "Account removed";
} on MsalException {
res = "Error signing out";
} on PlatformException catch (e) {
res = "some other exception ${e.toString()}";
}
print("setting state");
setState(() {
_output = res;
});
}
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
),
body: Center(
child: Column(
children: <Widget>[
ElevatedButton(
onPressed: _acquireToken,
child: Text('AcquireToken()'),
),
ElevatedButton(
onPressed: _loadAccount, child: Text('loadAccount()')),
ElevatedButton(
onPressed: _acquireTokenSilently,
child: Text('AcquireTokenSilently()')),
ElevatedButton(onPressed: _logout, child: Text('Logout')),
Text(_output),
Expanded(
child: ListView.builder(
itemCount: accounts?.length ?? 0,
itemBuilder: (context, index) {
final item = accounts![index];
return ListTile(
title: Text(item.username ?? item.identifier),
);
},
))
],
),
),
),
);
}
}
更多关于Flutter Azure认证插件msal_auth_azure的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter Azure认证插件msal_auth_azure的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
msal_auth_azure
是一个用于在 Flutter 应用中实现 Azure Active Directory (Azure AD) 认证的插件。它基于微软的 MSAL (Microsoft Authentication Library) 库,允许开发者轻松地将 Azure AD 认证集成到 Flutter 应用中。
以下是使用 msal_auth_azure
插件的基本步骤:
1. 添加依赖
首先,在 pubspec.yaml
文件中添加 msal_auth_azure
插件的依赖:
dependencies:
flutter:
sdk: flutter
msal_auth_azure: ^1.0.0 # 使用最新版本
然后运行 flutter pub get
来获取依赖。
2. 配置 Azure AD 应用
在 Azure 门户中创建一个应用程序注册,并获取以下信息:
- 客户端 ID (Client ID): 这是你的应用程序的唯一标识符。
- 租户 ID (Tenant ID): 这是你的 Azure AD 租户的唯一标识符。
- 重定向 URI (Redirect URI): 这是认证成功后用户被重定向的 URI。
3. 初始化 MSAL 客户端
在你的 Flutter 应用中,初始化 MsalAuthAzure
客户端:
import 'package:msal_auth_azure/msal_auth_azure.dart';
final msalAuthAzure = MsalAuthAzure(
clientId: 'YOUR_CLIENT_ID',
tenantId: 'YOUR_TENANT_ID',
redirectUri: 'YOUR_REDIRECT_URI',
);
4. 启动登录流程
使用 login()
方法来启动登录流程:
try {
final result = await msalAuthAzure.login();
print('Access Token: ${result.accessToken}');
print('ID Token: ${result.idToken}');
} catch (e) {
print('Login failed: $e');
}
5. 处理令牌
登录成功后,你可以获取 accessToken
和 idToken
,并使用它们来访问受保护的资源或进行用户身份验证。
6. 注销
使用 logout()
方法来注销用户:
await msalAuthAzure.logout();
7. 处理静默登录
在某些情况下,你可能希望在不提示用户的情况下尝试静默登录。可以使用 acquireTokenSilent()
方法:
try {
final result = await msalAuthAzure.acquireTokenSilent();
print('Access Token: ${result.accessToken}');
} catch (e) {
print('Silent login failed: $e');
}
8. 处理重定向 URI
在 Android 和 iOS 上,你需要配置重定向 URI 以处理认证回调。
Android
在 AndroidManifest.xml
中添加以下内容:
<activity android:name="com.azure.identity.msal.MsalActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="msauth" android:host="YOUR_PACKAGE_NAME" android:path="/YOUR_PATH" />
</intent-filter>
</activity>
iOS
在 Info.plist
中添加以下内容:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLSchemes</key>
<array>
<string>msauth.$(PRODUCT_BUNDLE_IDENTIFIER)</string>
</array>
</dict>
</array>