Flutter认证授权插件katana_auth的使用
Flutter认证授权插件katana_auth的使用

Katana Auth
[GitHub]
[YouTube]
[Packages]
[Twitter]
[Threads]
[LinkedIn]
[mathru.net]
简介
FirebaseAuthentication用于处理认证问题非常有用。
可以轻松实现各种类型的认证,包括通过电子邮件地址、电话号码和社交网络账户进行认证。
然而,即使以后可能会使用Firebase认证,也可能有以下需求:在创建应用程序的原型时,不连接到服务器的情况下实现认证;或者在测试代码中实现认证。
因此,我实现了一个包,可以通过适配器切换Firebase和本地认证,就像我在katana_model中做的那样。
此外,该接口得到了改进,使得根据应用程序的不同,可以轻松地切换Google登录和Apple登录。
安装
导入以下包:
flutter pub add katana_auth
如果使用Firestore,一起导入以下包:
flutter pub add katana_auth_firebase
实现
准备工作
始终将AuthAdapterScope
小部件放置在应用程序根附近。
传递一个AuthAdapter
,如RuntimeAuthAdapter
作为适配器参数。
// main.dart
import 'package:flutter/material.dart';
import 'package:katana_auth/katana_auth.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
[@override](/user/override)
Widget build(BuildContext context) {
return AuthAdapterScope(
adapter: const RuntimeAuthAdapter(),
child: MaterialApp(
home: const AuthPage(),
title: "Flutter Demo",
theme: ThemeData(
primarySwatch: Colors.blue,
),
),
);
}
}
创建认证对象
为了执行认证,首先创建一个Authentication
并将其保存在某个地方。
Authentication
对象可以获取以下数据来检查认证状态。
isSignedIn
:如果已认证,则返回true
。isAnonymously
:对于匿名认证返回true
。userId
:返回用户ID。userEmail
:如果执行了电子邮件认证等,则返回用户的电子邮件地址。userPhoneNumber
:如果执行了电话号码验证,则返回用户的电话号码。
此外,由于Authentication
继承了ChangeNotifier
,可以使用addListener
或riverpod的ChangeNotifierProvider
等来监控更新。
// auth_page.dart
import 'package:flutter/material.dart';
import 'package:katana_auth/katana_auth.dart';
class AuthPage extends StatefulWidget {
const AuthPage({super.key});
[@override](/user/override)
State<StatefulWidget> createState() => AuthPageState();
}
class AuthPageState extends State<AuthPage> {
final auth = Authentication();
[@override](/user/override)
void initState() {
super.initState();
auth.addListener(_handledOnUpdate);
}
void _handledOnUpdate() {
setState(() {});
}
[@override](/user/override)
void dispose() {
super.dispose();
auth.removeListener(_handledOnUpdate);
auth.dispose();
}
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("App Demo")),
body: ListView(
children: [
ListTile(
title: Text("SignedIn: ${auth.isSignedIn}"),
),
ListTile(
title: Text("Anonymously: ${auth.isAnonymously}"),
),
ListTile(
title: Text("ID: ${auth.userId}"),
),
ListTile(
title: Text("Email: ${auth.userEmail}"),
),
ListTile(
title: Text("Phone: ${auth.userPhoneNumber}"),
),
ListTile(
title: Text("Providers: ${auth.activeProviderIds?.join("\n")}"),
),
],
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (_) {
return AuthControlPage(auth: auth);
},
));
},
child: const Icon(Icons.person),
),
);
}
}
用户注册与登录
使用auth.register
方法来注册用户。
必须传递RegisterAuthProvider
作为参数。
RegisterAuthProvider
应该使用带有register
方法的AuthQuery
获得。
(AuthQuery
将在下面讨论。)
await auth.register(
EmailAndPasswordAuthQuery.register(
email: "test@email.com",
password: "12345678",
),
);
此外,使用auth.signIn
来执行登录。
必须传递SignInAuthProvider
作为参数,并应使用带有signIn
方法的AuthQuery
获得。
await auth.signIn(
EmailAndPasswordAuthQuery.signIn(
email: "test@email.com",
password: "12345678",
),
);
使用auth.confirmSignIn
来确认认证,例如进行邮件链接认证或SMS认证。
await auth.confirmSignIn(
SmsAuthQuery.confirmSignIn(
code: "012345",
),
);
更改用户信息
使用auth.change
来更改用户信息。
必须传递ChangeAuthProvider
作为参数,但可以根据要更改的内容改变AuthQuery
方法。
EmailAndPasswordAuthQuery.changeEmail
:更改电子邮件地址。EmailAndPasswordAuthQuery.changePassword
:更改密码。SmsAuthQuery.changePhoneNumber
:更改电话号码。
await auth.change(
EmailAndPasswordAuthQuery.changeEmail(
email: "changed@email.com"
),
);
(仅在登录后可用。)
注销
使用auth.signOut
来注销。
仅在登录后可用,无需任何参数。
await auth.signOut();
AuthAdapter
通过在定义AuthAdapterScope
时传递它,可以更改认证系统。
RuntimeAuthAdapter
:仅在应用程序启动时工作的认证系统。当应用程序重新启动时,会重置认证信息。测试时使用此系统。LocalAuthAdapter
:仅在设备上本地工作的认证系统。即使应用程序重新启动,认证信息也会保留,但不能与其他设备共享。FirebaseAuthAdapter
:FirebaseAuthentication系统。允许终端之间共享认证信息;需要初始Firebase配置。
AuthQuery
为每个认证提供商提供了AuthQuery
。
通过使用AuthQuery
方法,可以使用Authentication
类提供的认证功能。
(可用性受认证提供商限制。)
AnonymouslyAuthQuery
:提供匿名认证的AuthQuery
。EmailAndPasswordAuthQuery
:提供通过电子邮件地址和密码进行认证的AuthQuery
。EmailLinkAuthQuery
:提供通过电子邮件链接进行认证的AuthQuery
。SmsAuthQuery
:提供通过SMS进行认证的AuthQuery
。SnsSignInAuthProvider
:提供通过社交网络账户进行认证的AuthQuery
的抽象类。由于它是抽象类,实际的AuthQuery
可以通过加载其他相关包来使用。
GitHub赞助者
欢迎赞助。感谢您的支持!
https://github.com/sponsors/mathrunet
示例代码
// Flutter imports:
import 'package:flutter/material.dart';
// Package imports:
import 'package:katana_auth/katana_auth.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
[@override](/user/override)
Widget build(BuildContext context) {
return AuthAdapterScope(
adapter: const RuntimeAuthAdapter(),
child: MaterialApp(
home: const AuthPage(),
title: "Flutter Demo",
theme: ThemeData(
primarySwatch: Colors.blue,
),
),
);
}
}
class AuthPage extends StatefulWidget {
const AuthPage({super.key});
[@override](/user/override)
State<StatefulWidget> createState() => AuthPageState();
}
class AuthPageState extends State<AuthPage> {
final auth = Authentication();
[@override](/user/override)
void initState() {
super.initState();
auth.addListener(_handledOnUpdate);
}
void _handledOnUpdate() {
setState(() {});
}
[@override](/user/override)
void dispose() {
super.dispose();
auth.removeListener(_handledOnUpdate);
auth.dispose();
}
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("App Demo")),
body: ListView(
children: [
ListTile(
title: Text("SignedIn: ${auth.isSignedIn}"),
),
ListTile(
title: Text("Anonymously: ${auth.isAnonymously}"),
),
ListTile(
title: Text("ID: ${auth.userId}"),
),
ListTile(
title: Text("Email: ${auth.userEmail}"),
),
ListTile(
title: Text("Phone: ${auth.userPhoneNumber}"),
),
ListTile(
title: Text("Providers: ${auth.activeProviderIds?.join("\n")}"),
),
],
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (_) {
return AuthControlPage(auth: auth);
},
));
},
child: const Icon(Icons.person),
),
);
}
}
class AuthControlPage extends StatelessWidget {
const AuthControlPage({
required this.auth,
super.key,
});
final Authentication auth;
[@override](/user/override)
Widget build(BuildContext context) {
final navigator = Navigator.of(context);
return Scaffold(
appBar: AppBar(
title: const Text("Auth Control"),
),
body: ListView(
children: [
if (!auth.isSignedIn) ...[
if (!auth.isWaitingConfirmation) ...[
ListTile(
title: const Text("SignIn anonymously"),
onTap: () async {
await auth.signIn(AnonymouslyAuthQuery.signIn());
navigator.pop();
},
),
ListTile(
title: const Text("Register with email and password"),
onTap: () async {
await auth.register(
EmailAndPasswordAuthQuery.register(
email: "test@email.com",
password: "12345678",
),
);
navigator.pop();
},
),
ListTile(
title: const Text("SignIn with email and password"),
onTap: () async {
await auth.signIn(
EmailAndPasswordAuthQuery.signIn(
email: "test@email.com",
password: "12345678",
),
);
navigator.pop();
},
),
ListTile(
title: const Text("SignIn with email link"),
onTap: () async {
await auth.signIn(
EmailLinkAuthQuery.signIn(
email: "test@email.com",
url: "https://test.com",
),
);
navigator.pop();
},
),
ListTile(
title: const Text("SignIn with sms"),
onTap: () async {
await auth.signIn(
SmsAuthQuery.signIn(
phoneNumber: "01234567890",
countryNumber: "81",
),
);
navigator.pop();
},
),
] else ...[
ListTile(
title: const Text("Confirm signIn with email link"),
onTap: () async {
await auth.confirmSignIn(
EmailLinkAuthQuery.confirmSignIn(
url: "https://test.com",
),
);
navigator.pop();
},
),
ListTile(
title: const Text("Confirm signIn with sms"),
onTap: () async {
await auth.confirmSignIn(
SmsAuthQuery.confirmSignIn(
code: "012345",
),
);
navigator.pop();
},
),
],
] else ...[
if (!auth.isWaitingConfirmation) ...[
ListTile(
title: const Text("Change email"),
onTap: () async {
await auth.change(
EmailAndPasswordAuthQuery.changeEmail(
email: "changed@email.com"),
);
navigator.pop();
},
),
ListTile(
title: const Text("Change password"),
onTap: () async {
await auth.change(
EmailAndPasswordAuthQuery.changePassword(password: ""),
);
navigator.pop();
},
),
ListTile(
title: const Text("Change phoneNumber"),
onTap: () async {
await auth.change(
SmsAuthQuery.changePhoneNumber(
phoneNumber: "1234567890",
countryNumber: "81",
),
);
navigator.pop();
},
),
ListTile(
title: const Text("SignOut"),
onTap: () async {
await auth.signOut();
navigator.pop();
},
),
] else ...[
ListTile(
title: const Text("Confirm changing Phone number with sms"),
onTap: () async {
await auth.confirmChange(
SmsAuthQuery.confirmChangePhoneNumber(
code: "012345",
),
);
navigator.pop();
},
),
],
],
],
),
);
}
}
更多关于Flutter认证授权插件katana_auth的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter认证授权插件katana_auth的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是如何在Flutter应用中使用katana_auth
插件进行认证授权的示例代码。katana_auth
是一个强大的认证插件,可以帮助你快速实现用户认证和授权功能。假设你已经创建了一个Flutter项目,以下是实现基本认证功能的步骤和代码示例。
1. 添加依赖
首先,在你的pubspec.yaml
文件中添加katana_auth
依赖:
dependencies:
flutter:
sdk: flutter
katana_auth: ^latest_version # 请替换为最新版本号
然后运行flutter pub get
来安装依赖。
2. 配置KatanaAuth
在你的Flutter应用中,你需要初始化KatanaAuth
实例。通常在main.dart
文件中进行配置。
import 'package:flutter/material.dart';
import 'package:katana_auth/katana_auth.dart';
void main() {
// 初始化KatanaAuth
KatanaAuth.instance.init(
clientId: 'your-client-id', // 替换为你的客户端ID
clientSecret: 'your-client-secret', // 替换为你的客户端密钥
redirectUri: 'your-redirect-uri', // 替换为你的重定向URI
authorizationEndpoint: 'your-authorization-endpoint', // 替换为你的授权端点
tokenEndpoint: 'your-token-endpoint', // 替换为你的令牌端点
);
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: HomeScreen(),
);
}
}
3. 实现登录功能
在你的HomeScreen
或其他相关页面中,实现登录功能。
import 'package:flutter/material.dart';
import 'package:katana_auth/katana_auth.dart';
class HomeScreen extends StatefulWidget {
@override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
final _formKey = GlobalKey<FormState>();
String _email = '';
String _password = '';
void _login() async {
if (_formKey.currentState!.validate()) {
_formKey.currentState!.save();
try {
// 发起认证请求
var result = await KatanaAuth.instance.login(
username: _email,
password: _password,
);
// 处理认证结果
if (result.isSuccess) {
// 登录成功,可以保存令牌或使用令牌进行后续请求
print('Access Token: ${result.data?.accessToken}');
// 例如,你可以将令牌保存到本地存储或进行其他处理
} else {
// 登录失败,处理错误信息
print('Error: ${result.error?.message}');
}
} catch (e) {
print('Exception: $e');
}
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Login Screen'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
TextFormField(
decoration: InputDecoration(labelText: 'Email'),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter your email.';
}
return null;
},
onSaved: (value) {
_email = value!;
},
),
TextFormField(
decoration: InputDecoration(labelText: 'Password'),
obscureText: true,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter your password.';
}
return null;
},
onSaved: (value) {
_password = value!;
},
),
SizedBox(height: 20),
ElevatedButton(
onPressed: _login,
child: Text('Login'),
),
],
),
),
),
);
}
}
4. 处理登出和令牌刷新
你还可以实现登出功能以及令牌刷新功能。以下是如何实现登出的示例代码:
void _logout() async {
try {
await KatanaAuth.instance.logout();
// 处理登出后的逻辑,例如清除本地存储的令牌信息
print('User logged out successfully.');
} catch (e) {
print('Exception during logout: $e');
}
}
令牌刷新通常会在令牌即将过期时自动进行,但你也可以手动触发刷新:
void _refreshToken() async {
try {
var result = await KatanaAuth.instance.refreshToken();
if (result.isSuccess) {
// 令牌刷新成功,可以更新本地存储的令牌信息
print('New Access Token: ${result.data?.accessToken}');
} else {
// 令牌刷新失败,处理错误信息
print('Error refreshing token: ${result.error?.message}');
}
} catch (e) {
print('Exception during token refresh: $e');
}
}
以上示例展示了如何在Flutter应用中使用katana_auth
插件进行基本的认证授权操作。根据你的具体需求,你可以进一步扩展和自定义这些功能。