Skip to content

Instantly share code, notes, and snippets.

@magicleon94
Last active October 1, 2020 10:06
Show Gist options
  • Save magicleon94/4efb4bcbee6b377cf6d5c2ab4cb5a705 to your computer and use it in GitHub Desktop.
Save magicleon94/4efb4bcbee6b377cf6d5c2ab4cb5a705 to your computer and use it in GitHub Desktop.
Authentication Bloc: simple structure for having an auth BLoC with different flavors. Firebase flavor implemented for now. Only email/password auth for now.
import 'package:bloc/bloc.dart';
import 'package:my_app/features/auth/model/user.dart';
import 'package:meta/meta.dart';
part 'auth_event.dart';
part 'auth_state.dart';
abstract class AuthBloc extends Bloc<AuthEvent, AuthState> {
AuthBloc([AuthState initialState]) : super(initialState ?? AuthInitial());
}
part of 'auth_bloc.dart';
enum LoginType {
PASSWORD,
}
@immutable
abstract class AuthEvent {}
class AuthInit extends AuthEvent {}
class AuthLogin extends AuthEvent {
final String email;
final String password;
final LoginType loginType;
AuthLogin({
@required this.email,
@required this.password,
this.loginType = LoginType.PASSWORD,
});
}
class AuthLogout extends AuthEvent {}
part of 'auth_bloc.dart';
@immutable
abstract class AuthState {}
class AuthInitial extends AuthState {}
class AuthLoggedIn extends AuthState {
final User user;
AuthLoggedIn(this.user);
}
class AuthLoggedOut extends AuthState {}
class AuthError extends AuthState {
final Exception exception;
AuthError(this.exception);
}
import 'dart:async';
import 'package:my_app/features/auth/bloc/auth_bloc.dart';
import 'package:my_app/features/auth/model/user.dart';
import 'package:firebase_auth/firebase_auth.dart' as firebase;
import 'package:firebase_core/firebase_core.dart';
class FirebaseAuthBloc extends AuthBloc {
FirebaseAuthBloc() : super(AuthInitial());
firebase.FirebaseAuth auth;
Future<void> _init() async {
await Firebase.initializeApp();
auth = firebase.FirebaseAuth.instance;
}
@override
Stream<AuthState> mapEventToState(
AuthEvent event,
) async* {
try {
switch (event.runtimeType) {
case AuthInit:
await _init();
if (auth.currentUser != null) {
await refreshLogin();
final user = await User.fromFirebaseUser(auth.currentUser);
yield AuthLoggedIn(user);
} else {
yield AuthLoggedOut();
break;
}
break;
case AuthLogin:
final userCredential = await login(event);
final user = await User.fromFirebaseUser(userCredential.user);
yield AuthLoggedIn(user);
break;
case AuthLogout:
await auth.signOut();
yield AuthLoggedOut();
break;
default:
throw UnimplementedError();
}
} on Exception catch (e) {
yield AuthError(e);
}
}
Future<firebase.UserCredential> login(
AuthLogin event,
) async {
switch (event.loginType) {
case LoginType.PASSWORD:
return _loginWithEmailAndPassword(event.email, event.password);
break;
default:
throw UnimplementedError();
}
}
Future<firebase.UserCredential> _loginWithEmailAndPassword(
String email, String password) {
return auth.signInWithEmailAndPassword(email: email, password: password);
}
Future<void> refreshLogin() {
return auth.currentUser.reload();
}
}
import 'package:firebase_auth/firebase_auth.dart' as firebase;
import 'package:meta/meta.dart';
class User {
final String displayName;
final String email;
final bool emailVerified;
final String photoURL;
final String phoneNumber;
final bool isAnonymous;
final String idToken;
final String refreshToken;
User({
this.displayName,
this.email,
this.emailVerified,
this.photoURL,
this.phoneNumber,
this.isAnonymous,
@required this.idToken,
@required this.refreshToken,
});
static Future<User> fromFirebaseUser(firebase.User user) async => User(
displayName: user.displayName,
email: user.email,
emailVerified: user.emailVerified,
photoURL: user.photoURL,
phoneNumber: user.phoneNumber,
isAnonymous: user.isAnonymous,
idToken: await user.getIdToken(),
refreshToken: user.refreshToken,
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment