You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于OAuth2的Flutter应用集成Microsoft Azure单点登录问题咨询

Flutter集成Azure单点登录(SSO)问题解答

一、Azure应用注册配置

  • 应用类型:必须注册为移动和桌面应用,而非Web类型。Flutter属于跨平台移动端/桌面端范畴,Web类型仅适用于纯Web应用场景。
  • 特殊配置:
    • 在"身份验证"页面添加对应平台的重定向URI:
      • 移动端(Android/iOS):使用自定义URL Scheme,格式为msal{你的客户端ID}://auth
      • 桌面/调试场景:可配置http://localhost:3000/redirect或http://localhost
    • 开启"允许公共客户端流"(在"身份验证"的"高级设置"中),Flutter客户端属于公共客户端,无法安全存储密钥,必须开启此选项。

二、oauth2库的redirect()和listen()实现

oauth2库基于授权码流程实现SSO,redirect负责跳转至Azure授权页,listen负责监听授权回调并获取令牌。

1. redirect() 实现

通过url_launcher库打开Azure授权URL,引导用户完成登录授权:

import 'package:url_launcher/url_launcher.dart';
import 'package:oauth2/oauth2.dart';

// 替换为你的Azure租户ID、客户端ID
final tenantId = '你的租户ID';
final clientId = '你的客户端ID';
final redirectUri = Uri.parse('msal$clientId://auth'); // 与Azure配置的重定向URI一致

final authorizationEndpoint = Uri.parse('https://login.microsoftonline.com/$tenantId/oauth2/v2.0/authorize');
final tokenEndpoint = Uri.parse('https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token');

// 初始化授权客户端
final grant = AuthorizationCodeGrant(
  clientId,
  authorizationEndpoint,
  tokenEndpoint,
);

// 生成授权URL并跳转
Future<void> redirect() async {
  final authorizationUrl = grant.getAuthorizationUrl(redirectUri);
  if (await canLaunchUrl(authorizationUrl)) {
    await launchUrl(authorizationUrl);
  } else {
    throw Exception('无法打开授权页面');
  }
}

2. listen() 实现

根据平台差异,监听授权回调的方式不同:

  • 移动端:通过app_links库捕获URL Scheme回调:
import 'package:app_links/app_links.dart';

final appLinks = AppLinks();

Future<void> listen() async {
  appLinks.uriLinkStream.listen((Uri? uri) async {
    if (uri != null && uri.queryParameters.containsKey('code')) {
      // 用授权码交换令牌
      final client = await grant.handleAuthorizationResponse(uri.queryParameters);
      // 保存并使用令牌:client.credentials.accessToken、refreshToken等
      print('获取到访问令牌:${client.credentials.accessToken}');
    }
  });
}
  • 桌面/调试场景:用shelf库启动临时本地服务器接收localhost回调:
import 'package:shelf/shelf.dart';
import 'package:shelf/shelf_io.dart' as shelf_io;

Future<void> listen() async {
  final handler = const Pipeline().addHandler((Request request) async {
    if (request.requestedUri.queryParameters.containsKey('code')) {
      final client = await grant.handleAuthorizationResponse(request.requestedUri.queryParameters);
      // 处理令牌逻辑
      return Response.ok('登录成功,可关闭此页面');
    }
    return Response.ok('等待授权...');
  });

  // 启动本地服务器监听3000端口,与重定向URI端口一致
  await shelf_io.serve(handler, 'localhost', 3000);
}

三、localhost访问说明

  • 若重定向URI使用http://localhost格式,桌面端调试时必须启动本地Web服务器,用于接收Azure返回的授权码回调;
  • 移动端使用自定义URL Scheme作为重定向URI时,无需启动本地Web服务器,直接通过App的URL Scheme回调即可。

内容的提问来源于stack exchange,提问作者Sara Petrovic

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 12:54:20