Flutter LinkedIn登录插件linkedin_openid_login的使用
Flutter LinkedIn登录插件linkedin_openid_login的使用
简介
这个插件是基于 d3xt3r2909/linkedin_login 开发的,用于在Flutter应用中集成LinkedIn的OAuth 2.0 API。
安装
你可以通过以下命令安装此插件:
flutter pub add linkedin_openid_login
重要说明
在使用之前,你需要替换以下值:
final String redirectUrl = 'YOUR-REDIRECT-URL';
final String clientId = 'YOUR-CLIENT-ID';
final String clientSecret = 'YOUR-CLIENT-SECRET';
请注意,clientSecret
字段仅在 LinkedInUserWidget
中需要。
Hybrid Composition vs Virtual displays (Android Only)
要获取这些值,你需要在 LinkedIn开发者页面 创建一个应用。
请检查你的 minSdkVersion
:
- 如果你使用的是
Hybrid Composition
(从版本2.1.0开始默认),那么你的minSdkVersion
应该至少为19。 - 如果你想使用
Virtual displays
(在版本2.1.0之前默认),那么你的minSdkVersion
应该至少为20。
更多关于这两种模式的信息可以参阅 webview_flutter 的文档。
示例
你可以在 项目示例 查看完整的例子。
获取用户信息
LinkedInUserWidget(
redirectUrl: redirectUrl,
clientId: clientId,
clientSecret: clientSecret,
onGetUserProfile: (UserSucceededAction linkedInUser) {
print('Access token ${linkedInUser.user.token.accessToken}');
print('First name: ${linkedInUser.user.firstName.localized.label}');
print('Last name: ${linkedInUser.user.lastName.localized.label}');
},
onError: (UserFailedAction e) {
print('Error: ${e.toString()}');
},
)
获取授权码
LinkedInAuthCodeWidget(
redirectUrl: redirectUrl,
clientId: clientId,
onGetAuthCode: (AuthorizationSucceededAction response) {
print('Auth code ${response.codeResponse.code}');
print('State: ${response.codeResponse.state}');
},
onError: (AuthorizationFailedAction e) {
print('Error: ${e.toString()}');
},
)
如果你想要注销用户(清除会话),只需在 LinkedInUserWidget
或 LinkedInAuthCodeWidget
中将 destroySession
设置为 true
。同时,请确保在本地存储中销毁该用户的会话数据。目前,LinkedIn的OAuth 2.0 API尚不支持销毁访问令牌。
LinkedInUserWidget可用属性
String firstName;
String lastName;
String accessToken;
int expiresIn;
String profilePicture;
String email;
String userId; (从版本0.1.0开始)
投影 - 用户账户属性可通过LinkedIn API访问
从版本1.2.x开始,你可以通过提供字符串数组来控制投影,这些字符串数组可以通过 projection
属性传递给 LinkedInUserWidget
。默认情况下,这些属性包括:
static const String id = "id";
static const String localizedLastName = "localizedLastName";
static const String firstName = "firstName";
static const String lastName = "lastName";
static const String localizedFirstName = "localizedFirstName";
你还可以包含 profilePicture
来获取用户头像的URL。如果更改此属性为自定义值,则需要手动添加所有这些属性到数组中。更多信息请参阅示例项目。
范围 - 定义所需的范围
从版本2.3.1开始,你可以控制从LinkedIn获取的范围。默认情况下,你将拥有 r_emailaddress
和 r_liteprofile
,但如果你使用 scope
属性,可以在 LinkedInUserWidget
或 LinkedInAuthCodeWidget
中随时更改它。
final scopes = const [
EmailAddressScope(),
LiteProfileScope(),
];
你也可以通过扩展 Scope
类来创建自定义范围:
class CustomScope extends Scope {
const CustomScope() : super('r_emailaddress');
}
然而,请注意这个库在某些方面存在已知限制。
LinkedInAuthCodeWidget可用属性
String code; // 授权码
String state;
小部件
标准的LinkedIn登录按钮。这个小部件是可以修改的。
LinkedInButtonStandardWidget(onTap: () {});
贡献
要重新生成模拟文件和生成的文件,请运行以下命令:
flutter packages pub run build_runner build --delete-conflicting-outputs
已知限制
- 登录范围:主要与
w_member_social
相关。 - Firebase:由于Firebase不支持LinkedIn,因此此功能未在库中实现。
- Web:Web端尚未支持,因为LinkedIn不允许其API注入iFrame。
示例代码
main.dart
import 'package:flutter/material.dart';
import 'package:linkedin_openid_login/linkedin_openid_login.dart';
// ignore_for_file: avoid_print
void main() => runApp(const MyApp());
// [@TODO](/user/TODO) IMPORTANT - you need to change variable values below
// You need to add your own data from LinkedIn application
// From: https://www.linkedin.com/developers/
// Please read step 1 from this link https://developer.linkedin.com/docs/oauth2
// const String redirectUrl = 'https://www.youtube.com/callback';
const String redirectUrl =
'https://www.linkedin.com/developers/tools/oauth/redirect';
const String clientId = '';
const String clientSecret = '';
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
[@override](/user/override)
Widget build(final BuildContext context) {
return MaterialApp(
title: 'Flutter LinkedIn demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
title: const Text('LinkedIn Authorization Demo'),
),
body: const LinkedInProfileExamplePage(),
),
),
);
}
}
class LinkedInProfileExamplePage extends StatefulWidget {
const LinkedInProfileExamplePage({super.key});
[@override](/user/override)
State createState() => _LinkedInProfileExamplePageState();
}
class _LinkedInProfileExamplePageState
extends State<LinkedInProfileExamplePage> {
UserObject? user;
bool logoutUser = false;
[@override](/user/override)
Widget build(final BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
...(user == null
? [
LinkedInButtonStandardWidget(
onTap: () {
Navigator.push(
context,
MaterialPageRoute<void>(
builder: (final BuildContext context) =>
LinkedInUserWidget(
appBar: AppBar(
title: const Text('OAuth User'),
),
destroySession: logoutUser,
redirectUrl: redirectUrl,
clientId: clientId,
clientSecret: clientSecret,
projection: const [
ProjectionParameters.id,
ProjectionParameters.localizedFirstName,
ProjectionParameters.localizedLastName,
ProjectionParameters.firstName,
ProjectionParameters.lastName,
ProjectionParameters.profilePicture,
],
scope: const [
EmailAddressScope(),
LiteProfileScope(),
],
onError: (final UserFailedAction e) {
print('Error: ${e.toString()}');
print('Error: ${e.stackTrace.toString()}');
},
onGetUserProfile:
(final UserSucceededAction linkedInUser) {
user = UserObject(
firstName: linkedInUser.user.firstName,
lastName: linkedInUser.user.lastName,
email: linkedInUser.user.email,
profileImageUrl: linkedInUser.user.picture,
fullName: linkedInUser.user.name,
);
setState(() {
logoutUser = false;
});
Navigator.pop(context);
},
),
fullscreenDialog: true,
),
);
},
),
]
: [
Image.network(
user?.profileImageUrl ??
'https://beforeigosolutions.com/wp-content/uploads/2021/12/dummy-profile-pic-300x300-1.png',
height: 100,
width: 100,
fit: BoxFit.contain,
),
const SizedBox(height: 8),
Text('Name: ${user?.fullName} '),
Text('Given Name: ${user?.firstName} '),
Text('Family Name: ${user?.lastName} '),
Text('Email: ${user?.email}'),
const SizedBox(height: 15),
LinkedInButtonStandardWidget(
onTap: () {
setState(() {
user = null;
logoutUser = true;
});
},
buttonText: 'Logout',
),
])
],
),
);
}
}
class UserObject {
UserObject({
required this.firstName,
required this.lastName,
required this.email,
required this.profileImageUrl,
required this.fullName,
});
final String? firstName;
final String? lastName;
final String? email;
final String? profileImageUrl;
final String? fullName;
}
更多关于Flutter LinkedIn登录插件linkedin_openid_login的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter LinkedIn登录插件linkedin_openid_login的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,下面是一个关于如何在Flutter项目中使用linkedin_openid_login
插件来实现LinkedIn登录的示例代码。这个插件允许你通过OpenID Connect与LinkedIn进行身份验证。
首先,确保你已经在你的pubspec.yaml
文件中添加了linkedin_openid_login
依赖:
dependencies:
flutter:
sdk: flutter
linkedin_openid_login: ^x.y.z # 请替换为最新版本号
然后运行flutter pub get
来安装依赖。
接下来,你需要在LinkedIn开发者门户中创建一个应用并获取客户端ID和客户端密钥。一旦你有了这些信息,你就可以在你的Flutter应用中配置LinkedIn登录了。
以下是一个完整的示例代码,展示了如何使用linkedin_openid_login
插件:
import 'package:flutter/material.dart';
import 'package:linkedin_openid_login/linkedin_openid_login.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'LinkedIn Login Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: LinkedInLoginPage(),
);
}
}
class LinkedInLoginPage extends StatefulWidget {
@override
_LinkedInLoginPageState createState() => _LinkedInLoginPageState();
}
class _LinkedInLoginPageState extends State<LinkedInLoginPage> {
final LinkedInOpenIdLogin _linkedinOpenIdLogin = LinkedInOpenIdLogin(
clientId: 'YOUR_CLIENT_ID', // 替换为你的LinkedIn客户端ID
redirectUri: 'YOUR_REDIRECT_URI', // 替换为你的重定向URI
discoveryDocUrl: LinkedInOpenIdLogin.discoveryDocUrl, // 默认的发现文档URL
);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('LinkedIn Login'),
),
body: Center(
child: ElevatedButton(
onPressed: () async {
try {
String url = await _linkedinOpenIdLogin.getAuthorizationUrl();
// 这里你可以使用url_launcher包来在WebView或浏览器中打开这个URL
// 例如: await launch(url);
// 注意:为了简化示例,这里直接打印URL。在实际应用中,你应该在一个WebView中打开它。
print('Open this URL in a WebView or browser: $url');
// 用户完成登录并授权后,LinkedIn会重定向到你的redirectUri,并带上授权码
// 在实际应用中,你应该设置一个服务器来接收这个重定向请求,并交换访问令牌
// 这里为了演示,我们假设你已经有了授权码,并直接用它来交换访问令牌
String code = 'DUMMY_AUTHORIZATION_CODE'; // 替换为实际的授权码
LinkedInCredential credential = await _linkedinOpenIdLogin.getCredential(code);
print('LinkedIn Credential: ${credential.toJson()}');
} catch (e) {
print('Error: $e');
}
},
child: Text('Login with LinkedIn'),
),
),
);
}
}
// 注意:LinkedInCredential 类是假设的,实际插件可能提供不同的数据结构
class LinkedInCredential {
String accessToken;
String idToken;
// 其他字段...
Map<String, dynamic> toJson() {
return {
'accessToken': accessToken,
'idToken': idToken,
// 其他字段转换为JSON...
};
}
}
重要注意事项:
- 在实际应用中,你不应该在客户端代码中硬编码授权码。授权码应该通过你的服务器来获取和处理,以确保安全性。
- 上面的代码示例中,
getAuthorizationUrl()
方法返回的URL应该在WebView或系统浏览器中打开,而不是直接在应用内处理。用户完成登录并授权后,LinkedIn会重定向到你的redirectUri
,并带上授权码。你的服务器应该接收这个请求,并使用授权码来交换访问令牌。 - 由于安全原因,
redirectUri
必须是一个HTTPS URL,并且需要在LinkedIn开发者门户中预先配置。 LinkedInCredential
类是一个假设的类,用于演示目的。实际插件可能会提供不同的数据结构来表示从LinkedIn获取到的凭证。
请根据你的具体需求和安全要求来调整上述代码。