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

前言

在以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,再下次开发其他项目时候,就可以直接使用。方便快捷。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容