Flutter引入图形验证码,并保留SessionId
Posted HackShendi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Flutter引入图形验证码,并保留SessionId相关的知识,希望对你有一定的参考价值。
Hello,I’m Shendi
百度搜索不到相关内容,官网也没有相关内容,问群里大佬得到答案,这里记录一下
问题描述
登陆时需要使用到后端提供的图形验证码,后端通过 Session 保存验证码信息
Flutter 中提供了加载网络图片的方式,但没办法保存 SessionId,于是改变思路,用 dio 读取图片数据流,拿到 SessionId,再渲染到组件
解决
关于 dio 获取 SessionId 的方法可以参考这篇文章
https://shendi.blog.csdn.net/article/details/122510279
获取图片字节流的代码如下
LoginData
var cookie;
Map<String, String> session =
"name" : "",
"value" : "",
"domain" : "shendi"
;
var loginData = LoginData();
Future<Uint8List> getVCCode() async
dio.options.followRedirects = false;
dio.options.validateStatus = (status)
return status! < 500;
;
// 这里是设置Cookie,Cookie中包含SessionId
if (loginData.cookie != null) dio.options.headers["Cookie"] = loginData.cookie;
Response resp = await dio.get(
"验证码地址" + Random().nextInt(100).toString(),
options: Options(responseType: ResponseType.stream).timeout(const Duration(seconds: 3)));
// 如果有 set-cookie 则获取保存
if (resp.headers["set-cookie"] != null)
var cookie = resp.headers["set-cookie"].toString();
cookie = cookie.substring(1, cookie.length - 1);
loginData.cookie = cookie;
// 设置session结构, 目前COOKIE内容为 JSESSIONID=xxx; Path=/; HttpOnly
int len = cookie.indexOf('=');
loginData.session["name"] = cookie.substring(0, len);
cookie = cookie.substring(len);
len = cookie.indexOf(';');
loginData.session["value"] = cookie.substring(1, len);
cookie = cookie.substring(len+1);
final stream = await (resp.data as ResponseBody).stream.toList();
final result = BytesBuilder();
for (Uint8List subList in stream)
result.add(subList);
return result.takeBytes();
因为使用的 dio,获取到的返回是 Future<Uint8List>,我们需要拿到 Uint8List,需要使用到状态管理,可参考官网文档
https://book.flutterchina.club/chapter2/state_manage.html
这里我直接将我的登陆页代码贴上,供参考
/// 登陆页面
class Login extends StatelessWidget
const Login(Key? key) : super(key: key);
final appTitle = "登录 - Shendi";
@override
Widget build(BuildContext context)
return MaterialApp(
title: appTitle,
home: const LoginPage(),
);
/// 登录页面
class LoginPage extends StatefulWidget
const LoginPage(Key? key) : super(key: key);
@override
State<StatefulWidget> createState()
return LoginPageState();
/// 登陆状态
class LoginPageState extends State<LoginPage>
var account = TextEditingController();
var pwd = TextEditingController();
var code = TextEditingController();
var codeImg;
@override
void initState()
super.initState();
// 初始化验证码
flushVCCode();
eventBus.on<VCCodeFlush>().listen((event)
flushVCCode();
);
/// 刷新验证码
flushVCCode() async
var data = await http.getVCCode();
setState(()
codeImg = Image.memory(data);
);
@override
Widget build(BuildContext context)
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text(const Login().appTitle),
),
body: Padding(
padding: const EdgeInsets.all(20),
child: ListView(
children: [
TextFormField(
controller: account,
decoration: const InputDecoration(
labelText: "账号",
hintText: "请输入账号"
),
),
TextField(
controller: pwd,
decoration: const InputDecoration(
labelText: "密码",
hintText: "请输入密码"
),
),
Row(
children: [
Expanded(child: TextFormField(
controller: code,
decoration: const InputDecoration(
labelText: "验证码",
hintText: "请输入验证码"
),
)),
GestureDetector(
child: codeImg ?? Container(),
onTap: ()
flushVCCode();
,
)
],
),
Padding(
padding: const EdgeInsets.fromLTRB(0, 22, 0, 0),
child: ElevatedButton(
onPressed: () async
var msg;
if (pwd.text == "") msg = "请填写密码!";
if (account.text == "") msg = "请填写账号!";
if (code.text == "") msg = "请输入验证码!";
if (msg != null)
Fluttertoast.showToast(
msg: msg,
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.TOP,
timeInSecForiosWeb: 1,
fontSize: 16.0
);
return;
bool isLogin = await http.login(account.text, pwd.text, code.text);
if (isLogin)
// 登录成功,进入主页面
runApp(const RoomList());
,
child: const Text("登录")
),
)
],
),
)
);
END
以上是关于Flutter引入图形验证码,并保留SessionId的主要内容,如果未能解决你的问题,请参考以下文章