diff --git a/example/lib/main.dart b/example/lib/main.dart index e6e364c..8dd8108 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:twitter_login/twitter_login.dart'; + void main() { runApp(MyApp()); @@ -73,77 +73,77 @@ class _MyAppState extends State { /// Use Twitter API v1.1 Future login() async { - final twitterLogin = TwitterLogin( - /// Consumer API keys - apiKey: apiKey, + // final twitterLogin = TwitterLogin( + // /// Consumer API keys + // // apiKey: apiKey, - /// Consumer API Secret keys - apiSecretKey: apiSecretKey, + // /// Consumer API Secret keys + // // apiSecretKey: apiSecretKey, - /// Registered Callback URLs in TwitterApp - /// Android is a deeplink - /// iOS is a URLScheme - redirectURI: 'example://', - ); + // /// Registered Callback URLs in TwitterApp + // /// Android is a deeplink + // /// iOS is a URLScheme + // redirectURI: 'example://', + // ); /// Forces the user to enter their credentials /// to ensure the correct users account is authorized. /// If you want to implement Twitter account switching, set [force_login] to true /// login(forceLogin: true); - final authResult = await twitterLogin.login(); - switch (authResult.status) { - case TwitterLoginStatus.loggedIn: - // success - print('====== Login success ======'); - print(authResult.authToken); - print(authResult.authTokenSecret); - break; - case TwitterLoginStatus.cancelledByUser: - // cancel - print('====== Login cancel ======'); - break; - case TwitterLoginStatus.error: - case null: - // error - print('====== Login error ======'); - break; - } + // final authResult = await twitterLogin.login(); + // switch (authResult.status) { + // case TwitterLoginStatus.loggedIn: + // // success + // print('====== Login success ======'); + // print(authResult.authToken); + // print(authResult.authTokenSecret); + // break; + // case TwitterLoginStatus.cancelledByUser: + // // cancel + // print('====== Login cancel ======'); + // break; + // case TwitterLoginStatus.error: + // case null: + // // error + // print('====== Login error ======'); + // break; + // } } /// Use Twitter API v2. Future loginV2() async { - final twitterLogin = TwitterLogin( - /// Consumer API keys - apiKey: apiKey, + // final twitterLogin = TwitterLogin( + // /// Consumer API keys + // //apiKey: apiKey, - /// Consumer API Secret keys - apiSecretKey: apiSecretKey, + // /// Consumer API Secret keys + // // apiSecretKey: apiSecretKey, - /// Registered Callback URLs in TwitterApp - /// Android is a deeplink - /// iOS is a URLScheme - redirectURI: 'example://', - ); + // /// Registered Callback URLs in TwitterApp + // /// Android is a deeplink + // /// iOS is a URLScheme + // redirectURI: 'example://', + // ); /// Forces the user to enter their credentials /// to ensure the correct users account is authorized. /// If you want to implement Twitter account switching, set [force_login] to true /// login(forceLogin: true); - final authResult = await twitterLogin.loginV2(); - switch (authResult.status) { - case TwitterLoginStatus.loggedIn: - // success - print('====== Login success ======'); - break; - case TwitterLoginStatus.cancelledByUser: - // cancel - print('====== Login cancel ======'); - break; - case TwitterLoginStatus.error: - case null: - // error - print('====== Login error ======'); - break; - } + // final authResult = await twitterLogin.loginV2(); + // switch (authResult.status) { + // case TwitterLoginStatus.loggedIn: + // // success + // print('====== Login success ======'); + // break; + // case TwitterLoginStatus.cancelledByUser: + // // cancel + // print('====== Login cancel ======'); + // break; + // case TwitterLoginStatus.error: + // case null: + // // error + // print('====== Login error ======'); + // break; + // } } } diff --git a/lib/entity/auth_result.dart b/lib/entity/auth_result.dart index 7a8782a..1c86196 100644 --- a/lib/entity/auth_result.dart +++ b/lib/entity/auth_result.dart @@ -1,29 +1,26 @@ import 'dart:core'; -import 'package:twitter_login/entity/user.dart'; import 'package:twitter_login/src/twitter_login.dart'; /// The result when the Twitter login flow has completed. /// The login methods always return an instance of this class. class AuthResult { - /// constructor AuthResult({ String? authToken, - String? authTokenSecret, + String? authVerifier, required TwitterLoginStatus status, String? errorMessage, - User? user, }) : _authToken = authToken, - _authTokenSecret = authTokenSecret, + _authVerifier = authVerifier, _status = status, - _errorMessage = errorMessage, - _user = user; + _errorMessage = errorMessage; + /// The access token for using the Twitter APIs final String? _authToken; - //// The access token secret for using the Twitter APIs - final String? _authTokenSecret; + /// The access token secret for using the Twitter APIs + final String? _authVerifier; /// The status after a Twitter login flow has completed final TwitterLoginStatus? _status; @@ -31,12 +28,8 @@ class AuthResult { /// The error message when the log in flow completed with an error final String? _errorMessage; - /// Twitter Account user Info. - final User? _user; - String? get authToken => _authToken; - String? get authTokenSecret => _authTokenSecret; + String? get authVerifier => _authVerifier; TwitterLoginStatus? get status => _status; String? get errorMessage => _errorMessage; - User? get user => _user; } diff --git a/lib/src/twitter_login.dart b/lib/src/twitter_login.dart index 55f711e..9c7987a 100644 --- a/lib/src/twitter_login.dart +++ b/lib/src/twitter_login.dart @@ -1,12 +1,9 @@ import 'dart:async'; import 'dart:io'; -import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:twitter_login/entity/auth_result.dart'; -import 'package:twitter_login/entity/user.dart'; -import 'package:twitter_login/schemes/access_token.dart'; -import 'package:twitter_login/schemes/request_token.dart'; + import 'package:twitter_login/src/auth_browser.dart'; import 'package:twitter_login/src/exception.dart'; @@ -26,17 +23,9 @@ enum TwitterLoginStatus { class TwitterLogin { /// constructor TwitterLogin({ - required this.apiKey, - required this.apiSecretKey, required this.redirectURI, }); - /// Consumer API key - final String apiKey; - - /// Consumer API secret key - final String apiSecretKey; - /// Callback URL final String redirectURI; @@ -44,25 +33,9 @@ class TwitterLogin { static const _eventChannel = EventChannel('twitter_login/event'); static final Stream _eventStream = _eventChannel.receiveBroadcastStream(); - /// Logs the user - /// Forces the user to enter their credentials to ensure the correct users account is authorized. - Future login({bool forceLogin = false}) async { + ///使用更安全的登录交互方式 + Future login({required String oauthToken}) async { String? resultURI; - RequestToken requestToken; - try { - requestToken = await RequestToken.getRequestToken( - apiKey, - apiSecretKey, - redirectURI, - forceLogin, - ); - } on Exception { - throw PlatformException( - code: '400', - message: 'Failed to generate request token.', - details: 'Please check your APIKey or APISecret.', - ); - } final uri = Uri.parse(redirectURI); final completer = Completer(); @@ -89,140 +62,15 @@ class TwitterLogin { }, ); - try { - if (Platform.isIOS || Platform.isMacOS) { - /// Login to Twitter account with SFAuthenticationSession or ASWebAuthenticationSession. - resultURI = await authBrowser.doAuth(requestToken.authorizeURI, uri.scheme); - } else if (Platform.isAndroid) { - // Login to Twitter account with chrome_custom_tabs. - final success = await authBrowser.open(requestToken.authorizeURI, uri.scheme); - if (!success) { - throw PlatformException( - code: '200', - message: 'Could not open browser, probably caused by unavailable custom tabs.', - ); - } - resultURI = await completer.future; - await subscribe.cancel(); - } else { - throw PlatformException( - code: '100', - message: 'Not supported by this os.', - ); - } - - // The user closed the browser. - if (resultURI?.isEmpty ?? true) { - throw const CanceledByUserException(); - } - - final queries = Uri.splitQueryString(Uri.parse(resultURI!).query); - if (queries['error'] != null) { - throw Exception('Error Response: ${queries['error']}'); - } - - // The user cancelled the login flow. - if (queries['denied'] != null) { - throw const CanceledByUserException(); - } - - final token = await AccessToken.getAccessToken( - apiKey, - apiSecretKey, - queries, - ); - - if ((token.authToken?.isEmpty ?? true) || (token.authTokenSecret?.isEmpty ?? true)) { - return AuthResult( - authToken: token.authToken, - authTokenSecret: token.authTokenSecret, - status: TwitterLoginStatus.error, - errorMessage: 'Failed', - ); - } - - User? user; - - try { - user = await User.getUserData( - apiKey, - apiSecretKey, - token.authToken!, - token.authTokenSecret!, - ); - } on Exception { - debugPrint('The rate limit may have been reached or the API may be restricted.'); - } - - return AuthResult( - authToken: token.authToken, - authTokenSecret: token.authTokenSecret, - status: TwitterLoginStatus.loggedIn, - user: user, - ); - } on CanceledByUserException { - return AuthResult( - status: TwitterLoginStatus.cancelledByUser, - errorMessage: 'The user cancelled the login flow.', - ); - } catch (error) { - return AuthResult( - status: TwitterLoginStatus.error, - errorMessage: error.toString(), - ); - } - } - - Future loginV2({bool forceLogin = false}) async { - String? resultURI; - RequestToken requestToken; - try { - requestToken = await RequestToken.getRequestToken( - apiKey, - apiSecretKey, - redirectURI, - forceLogin, - ); - } on Exception { - throw PlatformException( - code: '400', - message: 'Failed to generate request token.', - details: 'Please check your APIKey or APISecret.', - ); - } - - final uri = Uri.parse(redirectURI); - final completer = Completer(); - late StreamSubscription subscribe; - - if (Platform.isAndroid) { - await _channel.invokeMethod('setScheme', uri.scheme); - subscribe = _eventStream.listen((data) async { - if (data['type'] == 'url') { - if (!completer.isCompleted) { - completer.complete(data['url']?.toString()); - } else { - throw const CanceledByUserException(); - } - } - }); - } - - final authBrowser = AuthBrowser( - onClose: () { - if (!completer.isCompleted) { - completer.complete(null); - } - }, - ); + final authorizeURI = 'https://api.twitter.com/oauth/authorize?oauth_token==$oauthToken'; try { if (Platform.isIOS || Platform.isMacOS) { /// Login to Twitter account with SFAuthenticationSession or ASWebAuthenticationSession. - resultURI = await authBrowser.doAuth(requestToken.authorizeURI, uri.scheme); + resultURI = await authBrowser.doAuth(authorizeURI, uri.scheme); } else if (Platform.isAndroid) { // Login to Twitter account with chrome_custom_tabs. - final success = await authBrowser.open(requestToken.authorizeURI, uri.scheme); + final success = await authBrowser.open(authorizeURI, uri.scheme); if (!success) { throw PlatformException( code: '200', @@ -253,39 +101,10 @@ class TwitterLogin { throw const CanceledByUserException(); } - final token = await AccessToken.getAccessToken( - apiKey, - apiSecretKey, - queries, - ); - - if ((token.authToken?.isEmpty ?? true) || (token.authTokenSecret?.isEmpty ?? true)) { - return AuthResult( - authToken: token.authToken, - authTokenSecret: token.authTokenSecret, - status: TwitterLoginStatus.error, - errorMessage: 'Failed', - ); - } - - User? user; - try { - user = await User.getUserDataV2( - apiKey, - apiSecretKey, - token.authToken!, - token.authTokenSecret!, - token.userId!, - ); - } on Exception { - debugPrint('The rate limit may have been reached or the API may be restricted.'); - } - return AuthResult( - authToken: token.authToken, - authTokenSecret: token.authTokenSecret, + authToken: queries['oauth_token'], + authVerifier: queries['oauth_verifier'], status: TwitterLoginStatus.loggedIn, - user: user, ); } on CanceledByUserException { return AuthResult(