前言
在以flutter为底的app项目中,用户登录,退出等认证必须做在flutter项目里,那么采用何种状态管理,来全局管理用户认证呢?
今天我就借助flutter_bloc这个库来搭建一套可以复用的成熟用户认证系统
搭建前夕准备
一、我们需要了解现有app有多少认证事件,那么常规来说,流程如下:
1、启动app,判断有无token,有token则跳转首页获取数据,无token则跳转需要授权页面如登录页
2、登录页登录,登陆后保存token,跳转首页
3、退出登录,删除token跳转需要授权页
那么总结起来就有三种事件
1、启动事件
2、登录事件
3、退出登录事件
二、那么有了认证事件,我们还需要有几个认证状态,有哪些状态呢,我来梳理一下:
1、在app启动后,需要初始化用户状态,那么用户当前是一个身份需要初始化的状态
2、如果有token,或者用户登录后那么用户就是一个已认证的状态
3、如果用户退出登录,那么用户当前是未认证的状态
三、咱们还需要做一个用户认证接口,接口主要是为了解耦,为了后期扩展能力、接口需要有哪些内容呢继续梳理一下:
1、是否有token,token是决定app是否认证的关键
2、删除token,退出登录需要删除
3、保存token,登录需要保存
4、跳转授权页面
5、跳转非授权页面
准备好如上工作,那么我们开始搭建用户认证系统吧
1、先编写认证事件:
part of 'authentication_bloc.dart';
//App认证事件,一般来说有三种,启动认证,登录认证,退出认证
abstract class AuthenticationEvent extends Equatable {
const AuthenticationEvent();
@override
List<Object?> get props => [];
}
//App启动事件
class AppStart extends AuthenticationEvent{}
//App登录事件
class LogIn extends AuthenticationEvent{
final String token;
LogIn(this.token);
@override
List<Object?> get props => [token];
@override
String toString() =>"LoggedIn { token: $token }";
}
//App退出事件
class LogOut extends AuthenticationEvent{}
2、编写认证状态
part of 'authentication_bloc.dart';
/// 认证状态
abstract class AuthenticationState extends Equatable {
const AuthenticationState();
@override
List<Object> get props => [];
}
/// - uninitialized - 身份验证未初始化
class AuthenticationUninitialized extends AuthenticationState {}
/// - authenticated - 认证成功
class AuthenticationAuthenticated extends AuthenticationState {}
/// - unauthenticated - 未认证
class AuthenticationUnauthenticated extends AuthenticationState {}
3、编写外部接口
abstract class IUserAuthentication{
bool hasToken();
void saveToken(String token);
void deleteToken();
void authPage();
void unAuthPage();
}
4、有了如上的内容咱们就可以编写核心逻辑bloc了
import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'i_user_authentication.dart';
part 'authentication_event.dart';
part 'authentication_state.dart';
class AuthenticationBloc extends Bloc<AuthenticationEvent, AuthenticationState> {
final IUserAuthentication iUserAuthentication;
/// 初始化认证是未认证状态
AuthenticationBloc(this.iUserAuthentication) : super(AuthenticationUninitialized());
@override
Stream<AuthenticationState> mapEventToState(
AuthenticationEvent event,
) async* {
if(event is AppStart){
// 判断是否有Token
if(iUserAuthentication.hasToken()){
yield AuthenticationAuthenticated();
} else {
yield AuthenticationUnauthenticated();
}
}else if(event is LogIn){
iUserAuthentication.saveToken(event.token);
yield AuthenticationAuthenticated();
}else if(event is LogOut){
iUserAuthentication.deleteToken();
yield AuthenticationUnauthenticated();
}
}
}
为了使用方便咱们需要做一个工具类来支撑外部使用
import 'package:flutter/widgets.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'authentication_bloc.dart';
class Authentication{
static TransitionBuilder init({
TransitionBuilder? builder,
}) {
return (BuildContext context, Widget? child) {
var widget = BlocListener<AuthenticationBloc, AuthenticationState>(
listener: (context, state) {
var bloc = BlocProvider.of<AuthenticationBloc>(context);
if (state is AuthenticationAuthenticated) {
bloc.iUserAuthentication.authPage();
} else if (state is AuthenticationUnauthenticated) {
bloc.iUserAuthentication.unAuthPage();
}
},
child: child,
);
if (builder != null) {
return builder(context, widget );
} else {
return widget;
}
};
}
}
使用
在项目中如何使用呢??
1、接口事件类
2、bloc初始化
3、监听初始化
代码如下:
接口实现类
class Auth implements IUserAuthentication{
static final String userTokenN = 'userToken';
Auth(){
_userMMKV = MMKVStore.appMMKV(name: "123");
}
@override
void authPage() {
RouterName.navigateTo(LibRouteNavigatorObserver.instance.navigator!.context, RouterName.home,clearStack: true);
}
late MMKV _userMMKV;
@override
void deleteToken() {
_userMMKV.removeValue(userTokenN);
}
@override
bool hasToken() {
return _userMMKV.decodeString(userTokenN)!=null;
}
@override
void saveToken(String token) {
_userMMKV.encodeString(userTokenN, token);
}
@override
void unAuthPage() {
RouterName.navigateTo(LibRouteNavigatorObserver.instance.navigator!.context, RouterName.login,replace: true);
}
}
2、初始化
MultiBlocProvider(
providers: [
//AuthenticationBloc bloc初始化
BlocProvider(create: (_) => AuthenticationBloc(Auth())),
],
child: MaterialApp(
...
builder: Authentication.init() //监听初始化
),
);
3、事件调用
1、退出按钮调用,BlocProvider.of<AuthenticationBloc>(context).add(LogOut())
2、登录页面调用,BlocProvider.of<AuthenticationBloc>(context).add(LogIn("123"))
3、SplashPage页面调用 BlocProvider.of<AuthenticationBloc>(context).add(AppStart())
大功告成
如上搭建的一个用户认证系统,可以抽离项目做成package,再下次开发其他项目时候,就可以直接使用。方便快捷。