概述
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问题描述解决的全部内容,希望文章能够帮你解决Flutter引入图形验证码,并保留SessionId问题描述解决所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复