Flutter OAuth2认证插件native_oauth2的使用
Flutter OAuth2认证插件native_oauth2的使用
native_oauth2
一个用于通过原生平台API使用OAuth 2.0进行身份验证的Flutter插件。
该包为在iOS(使用SFAuthenticationSession)和Android(使用Chrome Custom Tabs)上与OAuth 2.0提供程序进行身份验证提供了简单的接口。
安装
在pubspec.yaml
文件中添加native_oauth2
作为依赖项:
dependencies:
native_oauth2: ^0.1.1
然后运行以下命令以安装:
flutter pub get
Android设置
在AndroidManifest.xml
文件中的<activity>
标签内添加意图过滤器:
<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="custom-scheme"
android:host="custom.host"
android:path="/custom/path"/>
</intent-filter>
iOS设置
无需额外设置。
Web设置
当作为Web应用程序运行时,此插件提供两种模式:同一选项卡模式和弹出窗口模式。
同一选项卡模式
身份验证URL将在应用程序的同一选项卡中打开。不幸的是,这会导致所有应用程序状态丢失。为了使用此模式,您应该检查全局变量nativeOAuth2SameTabAuthResult
以查找重定向(见示例)。如果您使用PKCE,则应在运行authenticate
之前将代码验证器持久化到SessionStorage。
弹出窗口模式
身份验证URL将在弹出窗口中打开。一旦身份验证完成,重定向必须由静态HTML页面处理,并向源窗口发送消息。您应该创建一个像下面这样的HTML文件,并将其放在web/
目录的根目录下,然后设置您的重定向URI指向该页面。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Logged In</title>
</head>
<body>
<h1>You have been logged in. You will be redirected shortly</h1>
<script>
// 这是重要部分
// 您也可以在setTimeout中运行此代码,使用户感觉过程不那么突然
// 消息必须有一个名为redirect的属性,其值应为window.location.href
window.opener.postMessage({redirect: window.location.href}, window.location.origin)
window.close()
</script>
</body>
</html>
使用方法
使用任意OAuth 2.0提供程序进行身份验证:
import 'package:native_oauth2/native_oauth2.dart';
void login() async {
final plugin = NativeOAuth2();
final provider = OAuthProvider(
authUrlAuthority: authority,
authUrlPath: path,
clientId: clientId,
);
final result = await plugin.authenticate(
provider: provider,
redirectUri: Uri.parse('custom-scheme://custom.host/custom/path'),
scope: ['openid', 'Some.Other.Scope'],
);
}
示例代码
以下是完整的示例代码:
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:native_oauth2/native_oauth2.dart';
import 'package:pkce/pkce.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
[@override](/user/override)
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
[@override](/user/override)
Widget build(BuildContext context) {
return const MaterialApp(
home: MainPage(),
);
}
}
class MainPage extends StatefulWidget {
const MainPage({Key? key}) : super(key: key);
[@override](/user/override)
State<MainPage> createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
final _nativeOAuth2Plugin = NativeOAuth2();
bool loading = false;
final authority = '...'; // 替换为实际值
final path = '...'; // 替换为实际值
final clientId = '...'; // 替换为实际值
final redirectUri = Uri.parse('...'); // 替换为实际值
final scope = ['openid']; // 替换为实际值
[@override](/user/override)
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
if (kIsWeb) {
final sameTabAuthentication = nativeOAuth2SameTabAuthResult;
final redirect = sameTabAuthentication.redirect;
// 检查sameTabAuthentication的redirect是否匹配redirectUri
if (redirect.toString().startsWith(redirectUri.toString())) {
showSimpleDialog(sameTabAuthentication);
}
}
});
}
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Native OAuth2 Example App'),
),
body: Center(
child: Builder(
builder: (context) {
if (loading) {
return const CircularProgressIndicator();
} else {
return ElevatedButton(
onPressed: () => login(context),
child: const Text('LOGIN'),
);
}
},
),
),
);
}
void login(BuildContext context) async {
final provider = OAuthProvider(
authUrlAuthority: authority,
authUrlPath: path,
clientId: clientId,
);
final pkcePair = PkcePair.generate();
try {
setState(() {
loading = true;
});
final response = await _nativeOAuth2Plugin.authenticate(
provider: provider,
redirectUri: redirectUri,
scope: scope,
codeChallenge: pkcePair.codeChallenge,
codeChallengeMethod: 'S256',
prompt: 'select_account',
webMode: const WebAuthenticationMode.sameTab());
if (!mounted) return;
showSimpleDialog(response);
} finally {
setState(() {
loading = false;
});
}
}
void showSimpleDialog(Object? obj) {
showDialog(
context: context,
builder: (_) => AlertDialog(
content: Text(obj.toString()),
),
);
}
}
更多关于Flutter OAuth2认证插件native_oauth2的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter OAuth2认证插件native_oauth2的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
在Flutter中,native_oauth2
是一个用于处理OAuth2认证的插件。它允许你使用原生平台(如Android和iOS)的OAuth2库来进行认证,从而提供更好的用户体验和安全性。
1. 添加依赖
首先,你需要在 pubspec.yaml
文件中添加 native_oauth2
插件的依赖:
dependencies:
flutter:
sdk: flutter
native_oauth2: ^0.1.0 # 请使用最新版本
然后运行 flutter pub get
来安装依赖。
2. 配置OAuth2客户端
在使用 native_oauth2
之前,你需要配置OAuth2客户端。通常,你需要提供以下信息:
clientId
: 你的OAuth2客户端的ID。clientSecret
: 你的OAuth2客户端的密钥(可选,取决于OAuth2提供者)。redirectUri
: 重定向URI,用于接收授权码。authorizationEndpoint
: 授权端点的URL。tokenEndpoint
: 令牌端点的URL。scopes
: 请求的权限范围。
3. 使用 native_oauth2
进行认证
以下是一个简单的示例,展示如何使用 native_oauth2
进行OAuth2认证:
import 'package:flutter/material.dart';
import 'package:native_oauth2/native_oauth2.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: OAuth2Example(),
);
}
}
class OAuth2Example extends StatefulWidget {
@override
_OAuth2ExampleState createState() => _OAuth2ExampleState();
}
class _OAuth2ExampleState extends State<OAuth2Example> {
final OAuth2Client _oauth2Client = OAuth2Client(
clientId: 'your_client_id',
clientSecret: 'your_client_secret', // 可选
redirectUri: 'your_redirect_uri',
authorizationEndpoint: 'https://example.com/oauth/authorize',
tokenEndpoint: 'https://example.com/oauth/token',
scopes: ['read', 'write'],
);
String _accessToken = '';
Future<void> _authenticate() async {
try {
final OAuth2Response response = await _oauth2Client.authenticate();
setState(() {
_accessToken = response.accessToken;
});
} catch (e) {
print('Authentication failed: $e');
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('OAuth2 Example'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
if (_accessToken.isNotEmpty)
Text('Access Token: $_accessToken')
else
Text('Not authenticated'),
SizedBox(height: 20),
ElevatedButton(
onPressed: _authenticate,
child: Text('Authenticate'),
),
],
),
),
);
}
}
4. 处理重定向URI
在Android和iOS上,你需要配置应用来处理重定向URI。
Android
在 android/app/src/main/AndroidManifest.xml
文件中,添加以下内容:
<activity android:name="com.linusu.flutter_web_auth.CallbackActivity">
<intent-filter android:label="flutter_web_auth">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="your_redirect_uri_scheme" />
</intent-filter>
</activity>
iOS
在 ios/Runner/Info.plist
文件中,添加以下内容:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>your_redirect_uri_scheme</string>
</array>
</dict>
</array>
5. 处理令牌刷新
如果令牌过期,你可能需要刷新令牌。native_oauth2
提供了 refreshToken
方法来处理令牌刷新:
Future<void> _refreshToken() async {
try {
final OAuth2Response response = await _oauth2Client.refreshToken();
setState(() {
_accessToken = response.accessToken;
});
} catch (e) {
print('Token refresh failed: $e');
}
}
6. 处理注销
你可以使用 logout
方法来注销用户:
Future<void> _logout() async {
await _oauth2Client.logout();
setState(() {
_accessToken = '';
});
}