Skip to content

Commit

Permalink
Merge pull request #13 from finkmoritz/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
finkmoritz authored Aug 15, 2021
2 parents 2fa74f0 + 1f86833 commit e1c5622
Show file tree
Hide file tree
Showing 11 changed files with 140 additions and 27 deletions.
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
## 0.1.3
## 0.1.4 (2021-08-15)

- Add multi-factor authentication
- Fix third party provider support

## 0.1.3 (2021-07-16)

- Add PasswordChangePage
- Fix code formatting
Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Flutter plugin that automatically generates authentication widget templates based on your Amplify CLI Authentication configuration.

<img src="https://github.com/finkmoritz/flutter_amplify_auth_ui/raw/main/example/screenshots/SignInPage_light.png" alt="Preview" height="500px"/>
<img src="https://github.com/finkmoritz/flutter_amplify_auth_ui/raw/main/example/screenshots/Demo.gif" alt="Demo" height="500px"/>

## Features

Expand All @@ -16,6 +16,7 @@ Flutter plugin that automatically generates authentication widget templates base
- Facebook
- Google
- Amazon
- Sign in with multi-factor authentication (SMS)

### SignUpPage
- Sign up via password and one of the following (plus confirmation code):
Expand Down Expand Up @@ -58,7 +59,7 @@ Flutter plugin that automatically generates authentication widget templates base
To use this plugin, add `flutter_amplify_auth_ui` as a `dev_dependency` in your pubspec.yaml:
```
dev_dependencies:
flutter_amplify_auth_ui: ^0.1.3
flutter_amplify_auth_ui: ^0.1.4
```

Run `flutter pub get` to install the plugin.
Expand Down
Binary file added example/screenshots/Demo.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 12 additions & 4 deletions lib/src/auth_config/auth_config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,27 @@ class AuthConfig {
final bool allowUnauthenticatedIdentities;
final List<String> requiredAttributes;
final List<String> usernameAttributes;
final List<String> authProvidersUserPool;
final List<String> authProviders;
final String mfaConfiguration;
final List<String> mfaTypes;

const AuthConfig({
required this.allowUnauthenticatedIdentities,
required this.requiredAttributes,
required this.usernameAttributes,
required this.authProvidersUserPool,
required this.authProviders,
required this.mfaConfiguration,
required this.mfaTypes,
});

static AuthConfig fromJson(dynamic json) {
return AuthConfig(
allowUnauthenticatedIdentities: json['allowUnauthenticatedIdentities'],
requiredAttributes: _getAsList(json, 'requiredAttributes'),
usernameAttributes: _getAsList(json, 'usernameAttributes'),
authProvidersUserPool: _getAsList(json, 'authProvidersUserPool'),
authProviders: _getAsList(json, 'authProviders'),
mfaConfiguration: json['mfaConfiguration'],
mfaTypes: _getAsList(json, 'mfaTypes'),
);
}

Expand All @@ -30,7 +36,9 @@ class AuthConfig {
"allowUnauthenticatedIdentities": $allowUnauthenticatedIdentities,
"requiredAttributes": $requiredAttributes,
"usernameAttributes": $usernameAttributes,
"authProvidersUserPool": $authProvidersUserPool,
"authProviders": $authProviders,
"mfaConfiguration": $mfaConfiguration,
"mfaTypes": $mfaTypes,
''';
}
}
6 changes: 6 additions & 0 deletions lib/src/flutter_amplify_auth_ui_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ class FlutterAmplifyAuthUIGenerator {
Directory(targetDir).createSync();

CommandLine.printMessage('Generating classes...');
_generateClassFromTemplate(
targetDir: targetDir,
templateName: 'sign_in/confirmation_code_dialog.dart',
templateHandler: null,
authConfig: authConfig,
);
_generateClassFromTemplate(
targetDir: targetDir,
templateName: 'sign_in/sign_in_page.dart',
Expand Down
17 changes: 12 additions & 5 deletions lib/src/template_handlers/impl/sign_in_page_template_handler.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ class SignInPageTemplateHandler extends TemplateHandler {
'phone_number',
];
static const List<String> configurableAuthProviders = [
'Facebook',
'Google',
'LoginWithAmazon',
'graph.facebook.com',
'accounts.google.com',
'www.amazon.com',
];

@override
Expand All @@ -19,6 +19,7 @@ class SignInPageTemplateHandler extends TemplateHandler {
_handleUsernameAttributes(template: template, authConfig: authConfig);
_handleGuestSignIn(template: template, authConfig: authConfig);
_handleSignInWithWebUI(template: template, authConfig: authConfig);
_handleMfa(template: template, authConfig: authConfig);
}

void _handleUsernameAttributes(
Expand Down Expand Up @@ -47,12 +48,18 @@ class SignInPageTemplateHandler extends TemplateHandler {
void _handleSignInWithWebUI(
{required Template template, required AuthConfig authConfig}) {
configurableAuthProviders.forEach((provider) {
if (!authConfig.authProvidersUserPool.contains(provider)) {
if (!authConfig.authProviders.contains(provider)) {
template.remove(identifier: 'authProvidersUserPool[$provider]');
}
});
if (authConfig.authProvidersUserPool.isEmpty) {
if (authConfig.authProviders.isEmpty) {
template.remove(identifier: 'authProvidersUserPool[any]');
}
}

void _handleMfa(
{required Template template, required AuthConfig authConfig}) {
var reverseFlag = authConfig.mfaConfiguration == 'ON' ? 'OFF' : 'ON';
template.remove(identifier: 'mfaConfiguration[$reverseFlag]');
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,13 @@ class SignUpPageTemplateHandler extends TemplateHandler {

void _handleRequiredAttributes(
{required Template template, required AuthConfig authConfig}) {
var requiredAttributes = authConfig.requiredAttributes;
if (authConfig.mfaConfiguration == 'ON' &&
authConfig.mfaTypes.contains('SMS Text Message')) {
requiredAttributes.add('phone_number');
}
configurableRequiredAttributes.forEach((attribute) {
if (!authConfig.requiredAttributes.contains(attribute)) {
if (!requiredAttributes.contains(attribute)) {
template.remove(identifier: 'requiredAttributes[$attribute]');
}
});
Expand Down
75 changes: 75 additions & 0 deletions lib/templates/sign_in/confirmation_code_dialog.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import 'package:amplify_auth_cognito/amplify_auth_cognito.dart';
import 'package:amplify_flutter/amplify.dart';
import 'package:flutter/material.dart';

class ConfirmationCodeDialog extends StatefulWidget {
final void Function(BuildContext) onSignIn;

const ConfirmationCodeDialog({Key? key, required this.onSignIn})
: super(key: key);

@override
_ConfirmationCodeDialogState createState() => _ConfirmationCodeDialogState();
}

class _ConfirmationCodeDialogState extends State<ConfirmationCodeDialog> {
final TextEditingController _confirmationCodeController =
TextEditingController();

@override
void dispose() {
_confirmationCodeController.dispose();
super.dispose();
}

@override
Widget build(BuildContext context) {
return AlertDialog(
title: const Text('Confirmation Code'),
content: SingleChildScrollView(
child: Column(
children: [
Text('Please enter the confirmation code we sent you.'),
TextFormField(
controller: _confirmationCodeController,
keyboardType: TextInputType.number,
decoration: InputDecoration(
icon: Icon(Icons.check_outlined),
hintText: 'Enter your confirmation code',
labelText: 'Confirmation code'),
),
],
),
),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: const Text('Cancel'),
),
ElevatedButton(
onPressed: () {
_confirm();
},
child: const Text('Sign In'),
),
],
);
}

void _confirm() async {
try {
SignInResult result = await Amplify.Auth.confirmSignIn(
confirmationValue: _confirmationCodeController.text.trim(),
);
if (result.isSignedIn) {
Navigator.of(context).pop();
widget.onSignIn(context);
}
} on AuthException catch (e) {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text(e.message)));
}
}
}
29 changes: 19 additions & 10 deletions lib/templates/sign_in/sign_in_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'package:amplify_flutter/amplify.dart';
import 'package:flutter/material.dart';
import '../password_management/password_reset_page.dart';
import '../sign_up/sign_up_page.dart';
import 'confirmation_code_dialog.dart';

class SignInPage extends StatefulWidget {
final void Function(BuildContext) onSignIn;
Expand Down Expand Up @@ -138,7 +139,7 @@ class _SignInPageState extends State<SignInPage> {
ButtonBar(
alignment: MainAxisAlignment.center,
children: [
/*+++START authProvidersUserPool[Facebook]+++*/
/*+++START authProvidersUserPool[graph.facebook.com]+++*/
ElevatedButton(
onPressed: () =>
_signInWithWebUI(provider: AuthProvider.facebook),
Expand All @@ -149,8 +150,8 @@ class _SignInPageState extends State<SignInPage> {
),
child: Text('Sign in with Facebook'),
),
/*+++END authProvidersUserPool[Facebook]+++*/
/*+++START authProvidersUserPool[Google]+++*/
/*+++END authProvidersUserPool[graph.facebook.com]+++*/
/*+++START authProvidersUserPool[accounts.google.com]+++*/
ElevatedButton(
onPressed: () =>
_signInWithWebUI(provider: AuthProvider.google),
Expand All @@ -163,8 +164,8 @@ class _SignInPageState extends State<SignInPage> {
),
child: Text('Sign in with Google'),
),
/*+++END authProvidersUserPool[Google]+++*/
/*+++START authProvidersUserPool[LoginWithAmazon]+++*/
/*+++END authProvidersUserPool[accounts.google.com]+++*/
/*+++START authProvidersUserPool[www.amazon.com]+++*/
ElevatedButton(
onPressed: () =>
_signInWithWebUI(provider: AuthProvider.amazon),
Expand All @@ -175,7 +176,7 @@ class _SignInPageState extends State<SignInPage> {
),
child: Text('Sign in with Amazon'),
),
/*+++END authProvidersUserPool[LoginWithAmazon]+++*/
/*+++END authProvidersUserPool[www.amazon.com]+++*/
],
),
],
Expand All @@ -189,7 +190,7 @@ class _SignInPageState extends State<SignInPage> {
void _signIn() async {
try {
await Amplify.Auth.signOut();
SignInResult result = await Amplify.Auth.signIn(
await Amplify.Auth.signIn(
/*+++START usernameAttributes[username]+++*/
username: _usernameController.text.trim(),
/*+++END usernameAttributes[username]+++*/
Expand All @@ -201,9 +202,17 @@ class _SignInPageState extends State<SignInPage> {
+++END usernameAttributes[phone_number]+++*/
password: _passwordController.text.trim(),
);
if (result.isSignedIn) {
widget.onSignIn(context);
}
/*+++START mfaConfiguration[OFF]+++*/
widget.onSignIn(context);
/*+++END mfaConfiguration[OFF]+++*/
/*+++START mfaConfiguration[ON]+++*/
await showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return ConfirmationCodeDialog(onSignIn: widget.onSignIn);
});
/*+++END mfaConfiguration[ON]+++*/
} on AuthException catch (e) {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text(e.message)));
Expand Down
3 changes: 0 additions & 3 deletions lib/templates/sign_up/sign_up_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -586,9 +586,6 @@ class _SignUpPageState extends State<SignUpPage> {
}),
),
);
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('Successfully signed up'),
));
setState(() {
_stepIndex = 1;
});
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: flutter_amplify_auth_ui
description: Flutter plugin that automatically generates authentication widget templates based on your Amplify CLI Authentication configuration.
version: 0.1.3
version: 0.1.4
homepage: https://github.com/finkmoritz/flutter_amplify_auth_ui
repository: https://github.com/finkmoritz/flutter_amplify_auth_ui
issue_tracker: https://github.com/finkmoritz/flutter_amplify_auth_ui/issues
Expand Down

0 comments on commit e1c5622

Please sign in to comment.