注册

跟我学企业级flutter项目:用bloc手把手教你搭建用户认证系统

前言

跟我学flutter系列:
跟我学flutter:我们来举个例子通俗易懂讲解dart 中的 mixin
跟我学flutter:我们来举个例子通俗易懂讲解异步(一)ioslate
跟我学flutter:我们来举个例子通俗易懂讲解异步(二)ioslate循环机制
企业级篇目:
跟我学企业级flutter项目:用bloc手把手教你搭建用户认证系统
跟我学企业级flutter项目:dio网络框架增加公共请求参数&header
跟我学企业级flutter项目:如何用dio封装一套企业级可扩展高效的网络层
跟我学企业级flutter项目:如何封装一套易用,可扩展的Hybrid混合开发webview
跟我学企业级flutter项目:手把手教你制作一款低耦合空页面widget

在以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 get props => [];
}
//App启动事件
class AppStart extends AuthenticationEvent{}
//App登录事件
class LogIn extends AuthenticationEvent{
final String token;

LogIn(this.token);

@override
List 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 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 {

final IUserAuthentication iUserAuthentication;

/// 初始化认证是未认证状态
AuthenticationBloc(this.iUserAuthentication) : super(AuthenticationUninitialized());

@override
Stream 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(
listener: (context, state) {
var bloc = BlocProvider.of(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(context).add(LogOut()) 

2、登录页面调用,BlocProvider.of(context).add(LogIn("123")) 

3、SplashPage页面调用 BlocProvider.of(context).add(AppStart())


大功告成


如上搭建的一个用户认证系统,可以抽离项目做成package,再下次开发其他项目时候,就可以直接使用。方便快捷。

0 个评论

要回复文章请先登录注册