为了账号安全,请及时绑定邮箱和手机立即绑定

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

标签:
Android iOS

前言

在以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(context).add(LogOut())
2、登录页面调用,BlocProvider.of(context).add(LogIn(“123”))
3、SplashPage页面调用 BlocProvider.of(context).add(AppStart())

大功告成

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

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消