Flutter Firebase认证实现理发师/顾客双角色访问控制
美发服务应用双角色权限控制实现方案
整个实现分4步走,直接对应你现有代码改即可:
1. 扩展Auth Provider的角色管理能力
你现有Auth类只存了认证凭证,没有角色字段,而且signup方法预留的options参数完全没用到,先补全这部分逻辑:
- 首先在Auth类里新增角色私有字段和对外getter:
String? _userRole; String? get userRole => _userRole;
- 注册流程改造:原有
_authenticate方法执行成功拿到_userId后,用Firebase Firestore存用户额外信息,把用户注册时选择的角色写入users/[userId]文档,固定存role: 'barber'(理发师)或role: 'customer'(顾客)两个值 - 登录流程改造:认证成功拿到
_userId后,主动请求Firestore对应用户文档,拉取role字段赋值给_userRole - 登出时记得把
_userRole置空,所有角色字段更新后调用notifyListeners()触发UI刷新 - 改造后的signup方法示例:
Future<void> signup(String? email, String? password, String selectedRole) async { await _authenticate(email!, password!, 'signupNewUser'); // 注册成功后存角色到Firestore await FirebaseFirestore.instance.collection('users').doc(_userId).set({ 'email': email, 'role': selectedRole }); _userRole = selectedRole; notifyListeners(); }
- 改造后的login方法示例:
Future<void> login(String? email, String? password) async { await _authenticate(email!, password!, 'verifyPassword'); // 登录成功后拉取用户角色 final userDoc = await FirebaseFirestore.instance.collection('users').doc(_userId).get(); _userRole = userDoc.data()!['role']; notifyListeners(); }
2. 修复注册页的角色选择逻辑
你现有auth_screen.dart里的角色选项写的是Driver、Customer,默认值是Student,完全不符合业务,而且没有把选择器加到表单里,按下面修改:
- 先修正角色选项常量:
var roleOptions = ['Barber', 'Customer']; var _currentSelectedRole = "Customer";
- 在注册模式的「确认密码」输入框下方,加一个表单内的下拉选择器,仅在Signup模式显示,示例代码:
if (_authMode == AuthMode.Signup) DropdownButtonFormField<String>( value: _currentSelectedRole, items: roleOptions.map((role) { return DropdownMenuItem( value: role, child: Text(role == 'Barber' ? '我是理发师' : '我是顾客'), ); }).toList(), onChanged: (val) { setState(() { _currentSelectedRole = val!; }); }, onSaved: (val) { _authData['role'] = val!; }, )
- 注册提交时把选中的角色传给signup方法:
await Provider.of<Auth>(context, listen: false).signup( _authData['email'], _authData['password'], _authData['role'], );
3. 实现多层级权限控制
不要只做单一层的控制,分三层做避免越权:
- 入口路由控制:在main.dart的根Widget用Consumer监听Auth状态,未登录直接显示AuthScreen;已登录的话判断
userRole,理发师跳理发师端首页,顾客跳顾客端首页,不要共用同一个首页 - 路由拦截控制:在MaterialApp的onGenerateRoute回调里加校验,如果用户访问的是理发师专属路由,但当前角色是customer,直接重定向到顾客首页,防止用户手动输入路由地址越权访问
- 页面组件控制:同一个页面内需要区分角色显示的内容,直接用角色判断包裹组件即可,比如:
// 只有理发师能看到预约管理按钮 if (Provider.of<Auth>(context, listen: false).userRole == 'Barber') ElevatedButton(onPressed: (){}, child: Text('预约管理')) // 只有顾客能看到下单按钮 if (Provider.of<Auth>(context, listen: false).userRole == 'Customer') ElevatedButton(onPressed: (){}, child: Text('预约理发'))
- 重要提醒:前端的控制只是体验优化,一定要在Firestore配置安全规则,比如理发师专属数据只允许role为barber的用户读写,不然懂技术的用户可以直接绕过前端限制调接口改数据
4. 可选优化:本地持久化
可以用shared_preferences把token、userId、userRole、过期时间存在本地,App冷启动的时候先读本地缓存,凭证有效的话直接拉取用户信息进入对应首页,不用每次打开都重新登录。
内容的提问来源于stack exchange,提问作者Lloyd Wingrove
相关产品推荐
相关产品推荐

