Flutter应用实现微软登录“记住邮箱仅需输密码”功能咨询
实现Microsoft认证Flutter应用的邮箱记忆优化
核心思路
- 用持久化存储(如
shared_preferences)保存首次登录成功后的用户邮箱 - 调整Azure AD OAuth配置,利用
login_hint字段预填充已保存的邮箱,同时取消强制全流程重新认证的参数 - 登录成功后提取用户邮箱并存储,下次启动时自动加载并应用到认证流程
具体实现步骤
1. 添加依赖
在pubspec.yaml中添加shared_preferences依赖:
dependencies: flutter: sdk: flutter aad_oauth: ^x.x.x # 保持你当前使用的版本 shared_preferences: ^2.2.2
2. 修改登录页面代码
import 'package:flutter/material.dart'; import 'package:aad_oauth/aad_oauth.dart'; import 'package:aad_oauth/model/config.dart'; import 'package:aad_oauth/model/token.dart'; import 'package:shared_preferences/shared_preferences.dart'; import '../../provider/sign_in_provider.dart'; import '../SuccessScreen.dart'; class LoginScreen extends StatefulWidget { static final navigatorKey = GlobalKey<NavigatorState>(); @override _LoginScreenState createState() => _LoginScreenState(); } class _LoginScreenState extends State<LoginScreen> { late final AadOAuth oauth; late SharedPreferences _prefs; String? _savedEmail; @override void initState() { super.initState(); _initPrefsAndOAuth(); } Future<void> _initPrefsAndOAuth() async { // 初始化SharedPreferences _prefs = await SharedPreferences.getInstance(); _savedEmail = _prefs.getString('user_email'); // 配置OAuth final config = Config( tenant: '2f5964b2-44fc-420d-8974-7afab2aaxxxxx', clientId: 'ed4c80e3-847b-4b0a-85a9-c9686209xxxx', scope: 'openid profile email offline_access', redirectUri: 'https://dasundola.b2clogin.com/oauth2/nativeclient', navigatorKey: SignInProvider.navigatorKey, customParameters: { // 动态设置prompt:有保存邮箱时优先复用会话,无则引导完整登录 'prompt': _savedEmail != null ? 'select_account' : 'login', // 预填充已保存的邮箱 'login_hint': _savedEmail ?? '', // 移除max_age=0,避免强制重新认证 }, ); oauth = AadOAuth(config); setState(() {}); } void _login() async { try { // 移除登录前的强制logout,保留用户会话 // await oauth.logout(); // 执行登录 await oauth.login(); final token = await oauth.getIdToken(); final accessToken = await oauth.getAccessToken(); if (accessToken != null && token != null) { // 从ID Token中提取用户邮箱 final email = token.email; if (email != null) { // 保存邮箱到本地 await _prefs.setString('user_email', email); } Navigator.pushReplacement( context, MaterialPageRoute(builder: (context) => SuccessScreen()), ); } } catch (e) { _showLoginError(e.toString()); } } void _showLoginError(String message) { showDialog( context: context, builder: (context) => AlertDialog( title: const Text('Login Error'), content: Text(message), actions: [ TextButton( child: const Text('OK'), onPressed: () => Navigator.of(context).pop(), ), ], ), ); } @override Widget build(BuildContext context) { return Scaffold( body: Padding( padding: const EdgeInsets.all(24.0), child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ const SizedBox(height: 20), const Text( 'Sign in', style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold), textAlign: TextAlign.center, ), const SizedBox(height: 16), ElevatedButton( onPressed: _login, child: const Padding( padding: EdgeInsets.symmetric(vertical: 12), child: Text( 'Login with Microsoft', style: TextStyle(fontSize: 16), ), ), style: ElevatedButton.styleFrom( backgroundColor: Colors.blue[700], shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(4), ), ), ), // 可选:添加切换账号按钮,允许用户清除已保存邮箱 if (_savedEmail != null) TextButton( onPressed: () async { await _prefs.remove('user_email'); setState(() => _savedEmail = null); await _initPrefsAndOAuth(); }, child: const Text('Switch Account'), ), const SizedBox(height: 16), ], ), ), ); } @override void dispose() { // 移除自动logout,避免清除用户会话 // oauth.logout(); super.dispose(); } }
关键修改说明
- 持久化存储:通过
shared_preferences实现邮箱的跨启动保存 - OAuth配置优化:
- 移除
max_age: '0',不再强制每次重新走完整认证流程 - 动态设置
prompt参数:已保存邮箱时用select_account(复用现有会话,仅需验证密码/MFA),无邮箱时用login(引导完整登录) - 利用
login_hint预填充邮箱,减少用户重复输入操作
- 移除
- 登录流程调整:取消登录前的强制
logout,保留用户会话;登录成功后从ID Token提取邮箱并存储 - 可选功能:添加切换账号按钮,支持用户清除已保存邮箱并重新登录
内容的提问来源于stack exchange,提问作者Dasun Dola
相关产品推荐
相关产品推荐

