Github works
This commit is contained in:
parent
056d6809ed
commit
56598f33de
7 changed files with 167 additions and 68 deletions
2
.analysis-options
Normal file
2
.analysis-options
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
analyzer:
|
||||||
|
strong-mode: true
|
44
.gitignore
vendored
44
.gitignore
vendored
|
@ -27,3 +27,47 @@ doc/api/
|
||||||
pubspec.lock
|
pubspec.lock
|
||||||
|
|
||||||
log.txt
|
log.txt
|
||||||
|
### JetBrains template
|
||||||
|
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
|
||||||
|
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||||
|
|
||||||
|
# User-specific stuff:
|
||||||
|
.idea/**/workspace.xml
|
||||||
|
.idea/**/tasks.xml
|
||||||
|
.idea/dictionaries
|
||||||
|
|
||||||
|
# Sensitive or high-churn files:
|
||||||
|
.idea/**/dataSources/
|
||||||
|
.idea/**/dataSources.ids
|
||||||
|
.idea/**/dataSources.xml
|
||||||
|
.idea/**/dataSources.local.xml
|
||||||
|
.idea/**/sqlDataSources.xml
|
||||||
|
.idea/**/dynamic.xml
|
||||||
|
.idea/**/uiDesigner.xml
|
||||||
|
|
||||||
|
# Gradle:
|
||||||
|
.idea/**/gradle.xml
|
||||||
|
.idea/**/libraries
|
||||||
|
|
||||||
|
# Mongo Explorer plugin:
|
||||||
|
.idea/**/mongoSettings.xml
|
||||||
|
|
||||||
|
## File-based project format:
|
||||||
|
*.iws
|
||||||
|
|
||||||
|
## Plugin-specific files:
|
||||||
|
|
||||||
|
# IntelliJ
|
||||||
|
/out/
|
||||||
|
|
||||||
|
# mpeltonen/sbt-idea plugin
|
||||||
|
.idea_modules/
|
||||||
|
|
||||||
|
# JIRA plugin
|
||||||
|
atlassian-ide-plugin.xml
|
||||||
|
|
||||||
|
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||||
|
com_crashlytics_export_strings.xml
|
||||||
|
crashlytics.properties
|
||||||
|
crashlytics-build.properties
|
||||||
|
fabric.properties
|
||||||
|
|
7
.idea/runConfigurations/Github_Auth_Server.xml
Normal file
7
.idea/runConfigurations/Github_Auth_Server.xml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="Github Auth Server" type="DartCommandLineRunConfigurationType" factoryName="Dart Command Line Application" singleton="true">
|
||||||
|
<option name="filePath" value="$PROJECT_DIR$/example/github.dart" />
|
||||||
|
<option name="workingDirectory" value="$PROJECT_DIR$" />
|
||||||
|
<method />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
|
@ -1,55 +0,0 @@
|
||||||
import 'dart:convert';
|
|
||||||
import 'dart:io';
|
|
||||||
import 'package:angel_auth/angel_auth.dart';
|
|
||||||
import 'package:angel_diagnostics/angel_diagnostics.dart';
|
|
||||||
import 'package:angel_framework/angel_framework.dart';
|
|
||||||
import 'package:angel_framework/common.dart';
|
|
||||||
import 'package:angel_auth_oauth2/angel_auth_oauth2.dart';
|
|
||||||
import 'package:oauth2/oauth2.dart' as oauth2;
|
|
||||||
|
|
||||||
const Map<String, String> OAUTH2_CONFIG = const {
|
|
||||||
'callback': '<callback-url>',
|
|
||||||
'key': '<client-id>',
|
|
||||||
'secret': '<my-secret>',
|
|
||||||
'authorizationEndpoint': '<auth-url>',
|
|
||||||
'tokenEndpoint': '<token-url>'
|
|
||||||
};
|
|
||||||
|
|
||||||
main() async {
|
|
||||||
var app = new Angel()..use('/users', new TypedService<User>(new MapService()));
|
|
||||||
|
|
||||||
var auth = new AngelAuth(jwtKey: 'oauth2 example secret', allowCookie: false);
|
|
||||||
auth.deserializer =
|
|
||||||
(String idStr) => app.service('users').read(int.parse(idStr));
|
|
||||||
auth.serializer = (User user) async => user.id;
|
|
||||||
|
|
||||||
auth.strategies.add(new OAuth2Strategy('example_site', OAUTH2_CONFIG,
|
|
||||||
(oauth2.Client client) async {
|
|
||||||
var response = await client.get('/link/to/user/profile');
|
|
||||||
return JSON.decode(response.body);
|
|
||||||
}));
|
|
||||||
|
|
||||||
app.get('/auth/example_site', auth.authenticate('example_site'));
|
|
||||||
app.get(
|
|
||||||
'/auth/example_site/callback',
|
|
||||||
auth.authenticate('example_site',
|
|
||||||
new AngelAuthOptions(callback: (req, res, jwt) async {
|
|
||||||
// In real-life, you might include a pop-up callback script
|
|
||||||
res.write('Your JWT: $jwt');
|
|
||||||
})));
|
|
||||||
|
|
||||||
await app.configure(auth);
|
|
||||||
await app.configure(logRequests(new File('log.txt')));
|
|
||||||
await app.configure(profileRequests());
|
|
||||||
|
|
||||||
var server = await app.startServer(InternetAddress.LOOPBACK_IP_V4, 3000);
|
|
||||||
print('Listening on http://${server.address.address}:${server.port}');
|
|
||||||
}
|
|
||||||
|
|
||||||
class User extends Model {
|
|
||||||
String example_siteId;
|
|
||||||
|
|
||||||
User({String id, this.example_siteId}) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
}
|
|
81
example/github.dart
Normal file
81
example/github.dart
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
|
import 'package:angel_auth/angel_auth.dart';
|
||||||
|
import 'package:angel_diagnostics/angel_diagnostics.dart';
|
||||||
|
import 'package:angel_framework/angel_framework.dart';
|
||||||
|
import 'package:angel_framework/common.dart';
|
||||||
|
import 'package:angel_auth_oauth2/angel_auth_oauth2.dart';
|
||||||
|
import 'package:oauth2/oauth2.dart' as oauth2;
|
||||||
|
|
||||||
|
const AngelAuthOAuth2Options OAUTH2_CONFIG = const AngelAuthOAuth2Options(
|
||||||
|
callback: 'http://localhost:3000/auth/github/callback',
|
||||||
|
key: '6caeaf5d4c04936ec34f',
|
||||||
|
secret: '178360518cf9de4802e2346a4b6ebec525dc4427',
|
||||||
|
authorizationEndpoint: 'http://github.com/login/oauth/authorize',
|
||||||
|
tokenEndpoint: 'https://github.com/login/oauth/access_token');
|
||||||
|
|
||||||
|
main() async {
|
||||||
|
var app = new Angel();
|
||||||
|
app.lazyParseBodies = true;
|
||||||
|
app.use('/users', new MapService());
|
||||||
|
|
||||||
|
var auth = new AngelAuth(jwtKey: 'oauth2 example secret', allowCookie: false);
|
||||||
|
|
||||||
|
auth.deserializer = app.service('users').read;
|
||||||
|
auth.serializer = (User user) async => user.id;
|
||||||
|
|
||||||
|
auth.strategies.add(
|
||||||
|
new OAuth2Strategy('github', OAUTH2_CONFIG, (oauth2.Client client) async {
|
||||||
|
var response = await client.get('https://api.github.com/user');
|
||||||
|
var ghUser = JSON.decode(response.body);
|
||||||
|
var id = ghUser['id'];
|
||||||
|
|
||||||
|
Iterable<Map> matchingUsers = await app.service('users').index({
|
||||||
|
'query': {'githubId': id}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (matchingUsers.isNotEmpty) {
|
||||||
|
// Return the corresponding user, if it exists
|
||||||
|
return User.parse(matchingUsers.firstWhere((u) => u['githubId'] == id));
|
||||||
|
} else {
|
||||||
|
// Otherwise,create a user
|
||||||
|
return await app
|
||||||
|
.service('users')
|
||||||
|
.create({'githubId': id}).then(User.parse);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
app.get('/auth/github', auth.authenticate('github'));
|
||||||
|
app.get(
|
||||||
|
'/auth/github/callback',
|
||||||
|
auth.authenticate('github',
|
||||||
|
new AngelAuthOptions(callback: (req, res, jwt) async {
|
||||||
|
// In real-life, you might include a pop-up callback script.
|
||||||
|
//
|
||||||
|
// Use `confirmPopupAuthentication`, which is bundled with
|
||||||
|
// `package:angel_auth`.
|
||||||
|
res.write('Your JWT: $jwt');
|
||||||
|
})));
|
||||||
|
|
||||||
|
await app.configure(auth);
|
||||||
|
await app.configure(logRequests());
|
||||||
|
|
||||||
|
var server = await app.startServer(InternetAddress.LOOPBACK_IP_V4, 3000);
|
||||||
|
var url = 'http://${server.address.address}:${server.port}';
|
||||||
|
print('Listening on $url');
|
||||||
|
print('View user listing: $url/users');
|
||||||
|
print('Sign in via Github: $url/auth/github');
|
||||||
|
}
|
||||||
|
|
||||||
|
class User extends Model {
|
||||||
|
@override
|
||||||
|
String id;
|
||||||
|
int githubId;
|
||||||
|
|
||||||
|
User({this.id, this.githubId});
|
||||||
|
|
||||||
|
static User parse(Map map) =>
|
||||||
|
new User(id: map['id'], githubId: map['github_id']);
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() => {'id': id, 'github_id': githubId};
|
||||||
|
}
|
|
@ -23,19 +23,35 @@ final Validator OAUTH2_OPTIONS_SCHEMA = new Validator({
|
||||||
'scopes': "'scopes' must be an Iterable of strings. You provided: {{value}}"
|
'scopes': "'scopes' must be an Iterable of strings. You provided: {{value}}"
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/// Holds credentials and also specifies the means of authenticating users against a remote server.
|
||||||
class AngelAuthOAuth2Options {
|
class AngelAuthOAuth2Options {
|
||||||
String key, secret, authorizationEndpoint, tokenEndpoint, callback;
|
/// Your application's client key or client ID, registered with the remote server.
|
||||||
Iterable<String> scopes;
|
final String key;
|
||||||
|
|
||||||
AngelAuthOAuth2Options(
|
/// Your application's client secret, registered with the remote server.
|
||||||
|
final String secret;
|
||||||
|
|
||||||
|
/// The remote endpoint that prompts external users for authentication credentials.
|
||||||
|
final String authorizationEndpoint;
|
||||||
|
|
||||||
|
/// The remote endpoint that exchanges auth codes for access tokens.
|
||||||
|
final String tokenEndpoint;
|
||||||
|
|
||||||
|
/// The callback URL that the OAuth2 server should redirect authenticated users to.
|
||||||
|
final String callback;
|
||||||
|
|
||||||
|
/// Used to split application scopes. Defaults to `' '`.
|
||||||
|
final String delimiter;
|
||||||
|
final Iterable<String> scopes;
|
||||||
|
|
||||||
|
const AngelAuthOAuth2Options(
|
||||||
{this.key,
|
{this.key,
|
||||||
this.secret,
|
this.secret,
|
||||||
this.authorizationEndpoint,
|
this.authorizationEndpoint,
|
||||||
this.tokenEndpoint,
|
this.tokenEndpoint,
|
||||||
this.callback,
|
this.callback,
|
||||||
Iterable<String> scopes: const []}) {
|
this.delimiter: ' ',
|
||||||
this.scopes = scopes ?? [];
|
this.scopes: const []});
|
||||||
}
|
|
||||||
|
|
||||||
factory AngelAuthOAuth2Options.fromJson(Map json) =>
|
factory AngelAuthOAuth2Options.fromJson(Map json) =>
|
||||||
new AngelAuthOAuth2Options(
|
new AngelAuthOAuth2Options(
|
||||||
|
@ -85,7 +101,8 @@ class OAuth2Strategy implements AuthStrategy {
|
||||||
_options.key,
|
_options.key,
|
||||||
Uri.parse(_options.authorizationEndpoint),
|
Uri.parse(_options.authorizationEndpoint),
|
||||||
Uri.parse(_options.tokenEndpoint),
|
Uri.parse(_options.tokenEndpoint),
|
||||||
secret: _options.secret);
|
secret: _options.secret,
|
||||||
|
delimiter: _options.delimiter ?? ' ');
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future authenticate(RequestContext req, ResponseContext res,
|
Future authenticate(RequestContext req, ResponseContext res,
|
||||||
|
|
|
@ -11,3 +11,6 @@ dependencies:
|
||||||
oauth2: ^1.0.0
|
oauth2: ^1.0.0
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
angel_diagnostics: ^1.0.0-dev
|
angel_diagnostics: ^1.0.0-dev
|
||||||
|
dependency_overrides:
|
||||||
|
oauth2:
|
||||||
|
git: https://github.com/thosakwe/oauth2.git
|
Loading…
Reference in a new issue