Added Twitter OAuth1

This commit is contained in:
thomashii@dukefirehawk.com 2022-06-04 09:30:18 +08:00
parent a226d29514
commit c96980a887
9 changed files with 90 additions and 49 deletions

View file

@ -1,19 +0,0 @@
name: "angel3_auth_twitter"
version: 3.0.0
description: "package:angel3_auth strategy for Twitter login. Auto-signs requests."
homepage: "https://github.com/angel-dart/auth_twitter.git"
publish_to: none
environment:
sdk: ">=2.10.0 <3.0.0"
dependencies:
angel_auth: ^2.0.0
angel_framework: ^2.0.0
http: ^0.13.0
path: ^1.0.0
twitter:
git:
url: https://github.com/dukefirehawk/twitter.dart.git
ref: sdk-2.12.x
dev_dependencies:
logging: ^1.0.0
lints: ^1.0.0

View file

@ -1,5 +1,13 @@
# Change Log # Change Log
## 6.0.0-beta.1
* Updated to SDK 2.16.x
## 5.0.0
* Skipped release
## 4.0.0 ## 4.0.0
* Migrated to support Dart SDK 2.12.x NNBD * Migrated to support Dart SDK 2.12.x NNBD

View file

@ -1,10 +1,10 @@
# Angel3 Auth Twitter # Angel3 Twitter OAuth1
![Pub Version (including pre-releases)](https://img.shields.io/pub/v/angel3_auth_twitter?include_prereleases) ![Pub Version (including pre-releases)](https://img.shields.io/pub/v/angel3_auth_twitter?include_prereleases)
![Null Safety](https://img.shields.io/badge/null-safety-brightgreen)](<https://dart.dev/null-safety>) ![Null Safety](https://img.shields.io/badge/null-safety-brightgreen)](<https://dart.dev/null-safety>)
[![Gitter](https://img.shields.io/gitter/room/angel_dart/discussion)](https://gitter.im/angel_dart/discussion) [![Gitter](https://img.shields.io/gitter/room/angel_dart/discussion)](https://gitter.im/angel_dart/discussion)
[![License](https://img.shields.io/github/license/dukefirehawk/angel)](https://github.com/dukefirehawk/angel/tree/master/packages/auth_twitter/LICENSE) [![License](https://img.shields.io/github/license/dukefirehawk/angel)](https://github.com/dukefirehawk/angel/tree/master/packages/auth_twitter/LICENSE)
Angel3 authentication strategy for Twitter login. Angel3 authentication strategy using Twitter OAuth 1.0a.
See the [example](example/server.dart); See the [example](example/example.dart);

View file

@ -1,9 +1,9 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:angel_auth/angel_auth.dart'; import 'package:angel3_auth/angel3_auth.dart';
import 'package:angel_auth_twitter/angel_auth_twitter.dart'; import 'package:angel3_auth_twitter/angel3_auth_twitter.dart';
import 'package:angel_framework/angel_framework.dart'; import 'package:angel3_framework/angel3_framework.dart';
import 'package:angel_framework/http.dart'; import 'package:angel3_framework/http.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
class _User { class _User {
@ -38,7 +38,7 @@ void main() async {
'http://localhost:3000/auth/twitter/callback', 'http://localhost:3000/auth/twitter/callback',
), ),
(twit, req, res) async { (twit, req, res) async {
var response = await twit.twitterClient.get(Uri.parse( var response = await twit.client.get(Uri.parse(
'https://api.twitter.com/1.1/account/verify_credentials.json')); 'https://api.twitter.com/1.1/account/verify_credentials.json'));
var userData = json.decode(response.body) as Map; var userData = json.decode(response.body) as Map;
return _User(userData['screen_name'] as String); return _User(userData['screen_name'] as String);
@ -53,9 +53,7 @@ void main() async {
}, },
); );
app app.get('/', auth.authenticate('twitter'));
..fallback(auth.decodeJwt)
..get('/', auth.authenticate('twitter'));
app.get( app.get(
'/auth/twitter/callback', '/auth/twitter/callback',
@ -74,7 +72,7 @@ void main() async {
chain([ chain([
requireAuthentication<_User>(), requireAuthentication<_User>(),
(req, res) { (req, res) {
var user = req.container.make<_User>(); var user = req.container!.make<_User>();
res.write('Your Twitter handle is ${user.handle}'); res.write('Your Twitter handle is ${user.handle}');
return false; return false;
}, },

View file

@ -1,11 +1,12 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'package:angel_auth/angel_auth.dart'; import 'dart:io';
import 'package:angel_framework/angel_framework.dart'; import 'package:angel3_auth/angel3_auth.dart';
import 'package:angel3_framework/angel3_framework.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:oauth/oauth.dart' as oauth;
import 'package:path/path.dart' as p; import 'package:path/path.dart' as p;
import 'package:twitter/twitter.dart'; import 'package:oauth1/oauth1.dart' as oauth;
import 'package:dart_twitter_api/twitter_api.dart';
/// Authenticates users by connecting to Twitter's API. /// Authenticates users by connecting to Twitter's API.
class TwitterStrategy<User> extends AuthStrategy<User> { class TwitterStrategy<User> extends AuthStrategy<User> {
@ -15,7 +16,7 @@ class TwitterStrategy<User> extends AuthStrategy<User> {
/// A callback that uses Twitter to authenticate a [User]. /// A callback that uses Twitter to authenticate a [User].
/// ///
/// As always, return `null` if authentication fails. /// As always, return `null` if authentication fails.
final FutureOr<User> Function(Twitter, RequestContext, ResponseContext) final FutureOr<User> Function(TwitterApi, RequestContext, ResponseContext)
verifier; verifier;
/// A callback that is triggered when an OAuth2 error occurs (i.e. the user declines to login); /// A callback that is triggered when an OAuth2 error occurs (i.e. the user declines to login);
@ -25,17 +26,47 @@ class TwitterStrategy<User> extends AuthStrategy<User> {
/// The root of Twitter's API. Defaults to `'https://api.twitter.com'`. /// The root of Twitter's API. Defaults to `'https://api.twitter.com'`.
final Uri baseUrl; final Uri baseUrl;
oauth.Client _client; oauth.Client? _client;
/// The underlying [oauth.Client] used to query Twitter. /// The underlying [oauth.Client] used to query Twitter.
oauth.Client get client => _client; oauth.Client get client => _client!;
TwitterStrategy(this.options, this.verifier, this.onError, TwitterStrategy(this.options, this.verifier, this.onError,
{http.BaseClient client, Uri baseUrl}) {http.BaseClient? client, Uri? baseUrl})
: baseUrl = baseUrl ?? Uri.parse('https://api.twitter.com') { : baseUrl = baseUrl ?? Uri.parse('https://api.twitter.com') {
var tokens = oauth.Tokens( // define platform (server)
consumerId: options.clientId, consumerKey: options.clientSecret); final oauth.Platform platform = oauth.Platform(
_client = oauth.Client(tokens, client: client); '$baseUrl/oauth/request_token', // temporary credentials request
'$baseUrl/oauth/authorize', // resource owner authorization
'$baseUrl/oauth/access_token', // token credentials request
oauth.SignatureMethods.hmacSha1 // signature method
);
// define client credentials (consumer keys)
final oauth.ClientCredentials clientCredentials =
oauth.ClientCredentials(options.clientId, options.clientSecret);
// create Authorization object with client credentials and platform definition
final oauth.Authorization auth =
oauth.Authorization(clientCredentials, platform);
// request temporary credentials (request tokens)
auth.requestTemporaryCredentials('oob').then((res) {
// redirect to authorization page
print(
"Open with your browser: ${auth.getResourceOwnerAuthorizationURI(res.credentials.token)}");
// get verifier (PIN)
stdout.write("PIN: ");
String verifier = stdin.readLineSync() ?? '';
// request token credentials (access tokens)
return auth.requestTokenCredentials(res.credentials, verifier);
}).then((res) {
// create Client object
_client = oauth.Client(
platform.signatureMethod, clientCredentials, res.credentials);
});
} }
/// Handle a response from Twitter. /// Handle a response from Twitter.
@ -60,7 +91,7 @@ class TwitterStrategy<User> extends AuthStrategy<User> {
/// Get an access token. /// Get an access token.
Future<Map<String, String>> getAccessToken(String token, String verifier) { Future<Map<String, String>> getAccessToken(String token, String verifier) {
return _client.post( return client.post(
baseUrl.replace(path: p.join(baseUrl.path, 'oauth/access_token')), baseUrl.replace(path: p.join(baseUrl.path, 'oauth/access_token')),
headers: { headers: {
'accept': 'application/json' 'accept': 'application/json'
@ -75,7 +106,7 @@ class TwitterStrategy<User> extends AuthStrategy<User> {
/// Get a request token. /// Get a request token.
Future<Map<String, String>> getRequestToken() { Future<Map<String, String>> getRequestToken() {
return _client.post( return client.post(
baseUrl.replace(path: p.join(baseUrl.path, 'oauth/request_token')), baseUrl.replace(path: p.join(baseUrl.path, 'oauth/request_token')),
headers: { headers: {
'accept': 'application/json' 'accept': 'application/json'
@ -86,8 +117,8 @@ class TwitterStrategy<User> extends AuthStrategy<User> {
} }
@override @override
Future<User> authenticate(RequestContext req, ResponseContext res, Future<User?> authenticate(RequestContext req, ResponseContext res,
[AngelAuthOptions options]) async { [AngelAuthOptions? options]) async {
try { try {
if (options != null) { if (options != null) {
var result = await authenticateCallback(req, res, options); var result = await authenticateCallback(req, res, options);
@ -107,7 +138,7 @@ class TwitterStrategy<User> extends AuthStrategy<User> {
} }
} on TwitterAuthorizationException catch (e) { } on TwitterAuthorizationException catch (e) {
var result = await onError(e, req, res); var result = await onError(e, req, res);
await req.app.executeHandler(result, req, res); await req.app?.executeHandler(result, req, res);
await res.close(); await res.close();
return null; return null;
} }
@ -124,8 +155,13 @@ class TwitterStrategy<User> extends AuthStrategy<User> {
var token = req.queryParameters['oauth_token'] as String; var token = req.queryParameters['oauth_token'] as String;
var verifier = req.queryParameters['oauth_verifier'] as String; var verifier = req.queryParameters['oauth_verifier'] as String;
var loginData = await getAccessToken(token, verifier); var loginData = await getAccessToken(token, verifier);
var twitter = Twitter(this.options.clientId, this.options.clientSecret, var twitter = TwitterApi(
loginData['oauth_token'], loginData['oauth_token_secret']); client: TwitterClient(
consumerKey: this.options.clientId,
consumerSecret: this.options.clientSecret,
token: loginData['oauth_token'] ?? '',
secret: loginData['oauth_token_secret'] ?? ''));
return await this.verifier(twitter, req, res); return await this.verifier(twitter, req, res);
} on TwitterAuthorizationException catch (e) { } on TwitterAuthorizationException catch (e) {
return await onError(e, req, res); return await onError(e, req, res);

View file

@ -0,0 +1,18 @@
name: "angel3_auth_twitter"
description: Angel3 authentication strategy for Twitter login. Auto-signs requests.
version: 3.0.0
homepage: https://angel3-framework.web.app/
repository: https://github.com/dukefirehawk/angel/tree/master/packages/auth_twitter
publish_to: none
environment:
sdk: ">=2.16.0 <3.0.0"
dependencies:
angel3_auth: ^6.0.0
angel3_framework: ^6.0.0
http: ^0.13.0
path: ^1.0.0
oauth1: ^2.0.0
dart_twitter_api: ^0.5.6+1
dev_dependencies:
logging: ^1.0.0
lints: ^2.0.0