Flutter OAuth2认证插件angel3_auth_oauth2的使用
Flutter OAuth2认证插件angel3_auth_oauth2的使用
angel3_auth_oauth2
是一个用于通过 OAuth2 认证远程身份提供商(如 Facebook、Google、Azure AD 等)的库。下面是详细的使用步骤和示例代码。
使用
首先,创建一个选项对象:
configureServer(Angel app) async {
// 加载从 Map 中的数据,例如应用配置:
var opts = ExternalAuthOptions.fromMap(app.configuration['auth0'] as Map);
// 在现场创建:
var opts = ExternalAuthOptions(
clientId: '<client-id>',
clientSecret: '<client-secret>',
redirectUri: Uri.parse('<callback>'));
}
在成功认证后,我们需要在自己的应用程序中识别用户:
typedef OAuth2Verifier = FutureOr<User> Function(oauth2.Client, RequestContext, ResponseContext);
/// 您可以使用纯函数来创建一个查询给定服务的验证器。
OAuth2Verifier oauth2verifier(Service<User> userService) {
return (client) async {
var response = await client.get('https://api.github.com/user');
var ghUser = json.decode(response.body);
var id = ghUser['id'] as int;
var matchingUsers = await mappedUserService.index({
'query': {'github_id': id}
});
if (matchingUsers.isNotEmpty) {
// 返回相应的用户,如果存在的话。
return matchingUsers.first;
} else {
// 否则,创建一个新用户
return await mappedUserService.create(User(githubId: id));
}
};
}
现在,初始化一个 OAuth2Strategy
,使用选项和验证器。你还需要为该策略实例提供一个名称。可以考虑使用远程认证提供者的名称(例如 facebook
)。
configureServer(Angel app) {
auth.strategies['github'] = OAuth2Strategy(
options,
authorizationEndpoint,
tokenEndpoint,
yourVerifier,
// 当发生错误或用户拒绝请求时调用此函数。
(e, req, res) async {
res.write('Ooops: $e');
await res.close();
},
);
}
最后,将其连接到一个 AngelAuth
实例,并将其连接到一个 Angel
服务器。设置两个路由:
- 重定向用户到外部提供者。
- 作为回调并处理访问代码。
对于回调路由,您可能希望显示一个关闭弹出窗口的 HTML 页面。在这种情况下,使用 confirmPopupAuthentication
,它是 package:angel3_auth
的一部分,作为 callback
函数:
configureServer(Angel app) async {
// ...
var auth = AngelAuth<User>();
auth.strategies['github'] = oauth2Strategy;
// 重定向
app.get('/auth/github', auth.authenticate('github'));
// 回调
app.get('/auth/github/callback', auth.authenticate(
'github',
AngelAuthOptions(callback: confirmPopupAuthentication())
));
// 连接插件!!!
await app.configure(auth);
}
自定义作用域分隔符
这个包应该对大多数 OAuth2 提供商(如 Github 或 Dropbox)开箱即用。但是,如果您的 OAuth2 作用域由除默认值(' '
)之外的其他分隔符分隔,则可以在 OAuth2Strategy
构造函数中添加它:
configureServer(Angel app) async {
OAuth2Strategy(..., delimiter: ' ');
}
处理非 JSON 响应
许多 OAuth2 提供商没有遵循规范,并且不会返回 application/json
响应。
您可以添加一个 getParameters
回调来解析任意响应的内容:
OAuth2Strategy(
// ...
getParameters: (contentType, body) {
if (contentType.type == 'application') {
if (contentType.subtype == 'x-www-form-urlencoded')
return Uri.splitQueryString(body);
else if (contentType.subtype == 'json') return JSON.decode(body);
}
throw FormatException('Invalid content-type $contentType; expected application/x-www-form-urlencoded or application/json.');
}
);
示例代码
import 'dart:convert';
import 'package:angel3_auth/angel3_auth.dart';
import 'package:angel3_framework/angel3_framework.dart';
import 'package:angel3_framework/http.dart';
import 'package:angel3_auth_oauth2/angel3_auth_oauth2.dart';
import 'package:http_parser/http_parser.dart';
import 'package:logging/logging.dart';
var authorizationEndpoint =
Uri.parse('http://github.com/login/oauth/authorize');
var tokenEndpoint = Uri.parse('https://github.com/login/oauth/access_token');
var options = ExternalAuthOptions(
clientId: '6caeaf5d4c04936ec34f',
clientSecret: '178360518cf9de4802e2346a4b6ebec525dc4427',
redirectUri: Uri.parse('http://localhost:3000/auth/github/callback'),
);
/// Github 不正确地遵循 OAuth2 规范,因此这里有一个逻辑来解析他们的响应。
Map<String, dynamic> parseParamsFromGithub(MediaType contentType, String body) {
if (contentType.type == 'application') {
if (contentType.subtype == 'x-www-form-urlencoded') {
return Uri.splitQueryString(body);
} else if (contentType.subtype == 'json') {
return (json.decode(body) as Map).cast<String, String>();
}
}
throw FormatException(
'Invalid content-type $contentType; expected application/x-www-form-urlencoded or application/json.');
}
void main() async {
// 创建服务器实例。
var app = Angel();
var http = AngelHttp(app);
app.logger = Logger('angel')
..onRecord.listen((rec) {
print(rec);
if (rec.error != null) print(rec.error);
if (rec.stackTrace != null) print(rec.stackTrace);
});
// 创建一个存储用户数据的服务。
var userService = app.use('/users', MapService()).inner;
var mappedUserService = userService.map(User.parse, User.serialize);
// 设置认证插件。
var auth = AngelAuth<User>(
serializer: (user) async => user.id ?? '',
deserializer: (id) => mappedUserService.read(id),
jwtKey: 'oauth2 example secret',
allowCookie: false);
await app.configure(auth.configureServer);
/// 创建一个策略类的实例。
auth.strategies['github'] = OAuth2Strategy(
options,
authorizationEndpoint,
tokenEndpoint,
// 当用户接受请求以通过 Github 登录时调用此函数。
(client, req, res) async {
var response = await client.get(Uri.parse('https://api.github.com/user'));
var ghUser = json.decode(response.body);
var id = ghUser['id'] as int?;
var matchingUsers = await mappedUserService.index({
'query': {'github_id': id}
});
if (matchingUsers.isNotEmpty) {
// 返回相应的用户,如果存在的话。
return matchingUsers.first;
} else {
// 否则,创建一个新用户
return await mappedUserService.create(User(githubId: id));
}
},
// 当发生错误或用户拒绝请求时调用此函数。
(e, req, res) async {
res.write('Ooops: $e');
await res.close();
},
// 当与 Github 交互时必须传递此解析器函数。
//getParameters: parseParamsFromGithub,
);
// 挂载一些路由
app.get('/auth/github', auth.authenticate('github'));
app.get(
'/auth/github/callback',
auth.authenticate('github',
AngelAuthOptions(callback: (req, res, jwt) async {
// 在实际应用中,您可能会包含一个弹出回调脚本。
//
// 使用 `confirmPopupAuthentication`,它是 `package:angel_auth` 的一部分。
var user = req.container!.make<User>();
res.write('Your user info: ${user.toJson()}\n\n');
res.write('Your JWT: $jwt');
await res.close();
})));
// 开始监听。
await http.startServer('127.0.0.1', 3000);
print('Listening on ${http.uri}');
print('View user listing: ${http.uri}/users');
print('Sign in via Github: ${http.uri}/auth/github');
}
class User extends Model {
int? githubId;
User({super.id, this.githubId});
static User parse(Map<String, dynamic> map) =>
User(id: map['id'] as String?, githubId: map['github_id'] as int?);
static Map<String, dynamic> serialize(User user) => user.toJson();
Map<String, dynamic> toJson() => {'id': id, 'github_id': githubId};
}
更多关于Flutter OAuth2认证插件angel3_auth_oauth2的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter OAuth2认证插件angel3_auth_oauth2的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是如何在Flutter项目中使用angel3_auth_oauth2
插件进行OAuth2认证的示例代码。需要注意的是,angel3_auth_oauth2
是一个Dart包,通常用于Dart后端服务,但如果你需要在Flutter前端处理OAuth2认证,通常会结合Flutter的HTTP客户端和OAuth2库(比如oauth2
包)来实现。不过,为了贴近你的要求,我将展示如何使用angel3_auth_oauth2
在Dart后端服务中进行OAuth2认证,并通过Flutter前端调用该服务。
后端(Dart/Angel Framework)
首先,确保你的pubspec.yaml
文件中包含以下依赖:
dependencies:
angel_framework: ^4.0.0
angel3_auth: ^3.0.0
angel3_auth_oauth2: ^3.0.0
然后,创建一个Dart文件(例如server.dart
),并设置OAuth2认证:
import 'package:angel_framework/angel_framework.dart';
import 'package:angel3_auth/angel3_auth.dart';
import 'package:angel3_auth_oauth2/angel3_auth_oauth2.dart';
void main() async {
var app = Angel();
// 配置AngelAuth
var auth = AngelAuth(app);
auth.serializers!.add(OAuth2Serializer('google'));
// 配置OAuth2
var googleOAuth2 = OAuth2Service(
clientId: 'YOUR_CLIENT_ID',
clientSecret: 'YOUR_CLIENT_SECRET',
authorizationEndpoint: 'https://accounts.google.com/o/oauth2/auth',
tokenEndpoint: 'https://www.googleapis.com/oauth2/v4/token',
redirectUri: 'http://localhost:3000/auth/google/callback',
scopes: ['email', 'profile'],
);
auth.configure('google', googleOAuth2);
// 处理OAuth2回调
app.get('/auth/google/callback', (req, res) async {
var result = await auth.authenticate('google', req);
if (result is AuthenticatedUser) {
// 用户已认证
res.write('Hello, ${result.user!.id}');
} else {
// 认证失败
res.status = 401;
res.write('Authentication failed');
}
});
// 启动服务器
await app.listen(3000);
print('Server listening on port 3000');
}
在这个示例中,我们配置了一个Google OAuth2服务,并设置了回调处理。你需要替换YOUR_CLIENT_ID
和YOUR_CLIENT_SECRET
为你的Google OAuth2客户端ID和密钥。
前端(Flutter)
在Flutter前端,你需要使用HTTP客户端(如http
包)来重定向用户到OAuth2认证页面,并处理回调。以下是一个简单的Flutter示例:
首先,在pubspec.yaml
中添加http
依赖:
dependencies:
flutter:
sdk: flutter
http: ^0.13.3
然后,创建一个Flutter页面(例如main.dart
),并添加以下代码:
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:uri';
import 'dart:convert';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: OAuth2Page(),
);
}
}
class OAuth2Page extends StatefulWidget {
@override
_OAuth2PageState createState() => _OAuth2PageState();
}
class _OAuth2PageState extends State<OAuth2Page> {
void _openOAuth2Login() async {
String clientId = 'YOUR_CLIENT_ID';
String redirectUri = Uri.encodeFull('http://localhost:3000/auth/google/callback');
String authUrl = Uri(
scheme: 'https',
host: 'accounts.google.com',
path: '/o/oauth2/auth',
queryParameters: {
'response_type': 'code',
'client_id': clientId,
'redirect_uri': redirectUri,
'scope': 'email profile',
'access_type': 'online',
},
).toString();
// 在WebView或系统浏览器中打开authUrl
if (await canLaunch(authUrl)) {
await launch(authUrl);
} else {
throw 'Could not launch $authUrl';
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('OAuth2 Login'),
),
body: Center(
child: ElevatedButton(
onPressed: _openOAuth2Login,
child: Text('Login with Google'),
),
),
);
}
}
在这个Flutter示例中,我们定义了一个简单的页面,其中包含一个按钮,点击该按钮会打开Google OAuth2认证页面。请注意,这个示例假设用户在认证后会被重定向回http://localhost:3000/auth/google/callback
,这在实际应用中可能不太现实,特别是在移动设备上。因此,你可能需要设置一个更合适的回调URL,或者使用其他方法来处理认证回调(例如,使用设备上的自定义URL方案或深度链接)。
注意:在实际应用中,处理OAuth2回调通常涉及更复杂的逻辑,包括处理错误、存储访问令牌、刷新令牌等。此外,由于angel3_auth_oauth2
主要用于服务器端,你可能需要在Flutter前端使用专门的OAuth2客户端库(如flutter_oauth2
)来处理认证流程。上面的示例主要用于演示基本概念,并可能需要根据你的具体需求进行调整。