Я пишу приложение для подключения к Proxmox во Flutter, и мне нужно получить различные области аутентификации. Проблема, с которой я столкнулся, заключается в том, что большинство серверов используют самозаверяющий сертификат SSL, а импорт http
не поддерживает это. Это заставило меня использовать пакет dart:io
и его HttpClient
. Однако использование этого метода не возвращает никаких результатов, список равен нулю.
D/ ( 9335): HostConnection::get() New Host Connection established 0xe047c540, tid 9354
D/EGL_emulation( 9335): eglMakeCurrent: 0xe76a7ac0: ver 3 0 (tinfo 0xccd07000)
I/flutter ( 9335): ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
I/flutter ( 9335): The following NoSuchMethodError was thrown building FormField<dynamic>(dirty, state:
I/flutter ( 9335): FormFieldState<dynamic>#11694):
I/flutter ( 9335): The method 'map' was called on null.
I/flutter ( 9335): Receiver: null
I/flutter ( 9335): Tried calling: map<DropdownMenuItem<String>>(Closure: (AuthRealm) => DropdownMenuItem<String>)
Это мой клиент класс:
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:Proxcontrol/Client/Objects/auth_realms.dart';
class Client {
String baseUrl;
Client(String url, String port) {
baseUrl = "https://" + url + ":" + port + "/api2/json/";
}
Future<List<AuthRealm>> getAuthRealms() async {
HttpClient client = new HttpClient();
client.badCertificateCallback =((X509Certificate cert, String host, int port) => true);
var request = await client.getUrl(Uri.parse(baseUrl + "access/domains"));
var response = await request.close();
return await response.transform(Utf8Decoder()).transform(JsonDecoder()).map((json) => AuthRealm.fromJson(json)).toList();
}
}
Это мой класс объектов AuthRealm, которому сопоставлен запрос:
class AuthRealm {
final String type;
final String realm;
final String comment;
AuthRealm({this.type, this.realm, this.comment});
factory AuthRealm.fromJson(Map<String, dynamic> json) {
return AuthRealm(
type: json['type'],
realm: json['realm'],
comment: json['comment']
);
}
}
И именно здесь я пытаюсь получить области аутентификации. Затем он передает их на новую страницу, где они отображаются в выпадающем меню. Поля serverAddress
и serverPort
заполняются через TextFields.
final nextButton = RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(24)),
onPressed: () {
Client client = new Client(serverAddress, serverPort);
client.getAuthRealms().then((values) {
realms = values;
});
Navigator.push(
context,
MaterialPageRoute(builder: (context) => ServerAuthLoginScreen(authRealms: realms)));
},
padding: EdgeInsets.all(10),
color: Colors.indigoAccent,
child: Text('NEXT', style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
);
И, наконец, раздел раскрывающейся кнопки, который заполняется областями аутентификации при загрузке этого экрана.
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:Proxcontrol/Client/Objects/auth_realms.dart';
class ServerAuthLoginScreen extends StatefulWidget {
final List<AuthRealm> authRealms;
const ServerAuthLoginScreen({Key key, @required this.authRealms}) : super(key: key);
@override
_ServerAuthLoginScreenState createState() => _ServerAuthLoginScreenState(authRealms);
}
class _ServerAuthLoginScreenState extends State<ServerAuthLoginScreen> {
List<AuthRealm> authRealms;
_ServerAuthLoginScreenState(this.authRealms);
String serverRealm;
@override
Widget build(BuildContext context) {
double screenWidth = MediaQuery.of(context).size.width;
double screenHeight = MediaQuery.of(context).size.height;
final realmSelector = FormField(
builder: (FormFieldState state) {
return InputDecorator(
decoration: InputDecoration(
icon: const Icon(FontAwesomeIcons.server),
labelText: 'Select an Auth Realm'),
isEmpty: serverRealm == '',
child: new DropdownButtonHideUnderline(
child: new DropdownButton(
isDense: true,
items: authRealms.map((AuthRealm value) {
return new DropdownMenuItem(
value: value.realm,
child: Text(value.realm),
);
}).toList(),
onChanged: (String value) {
setState(() {
serverRealm = value;
state.didChange(value);
});
}
)
),
);
},
);
_buildVerticalLayout() {
return ListView(
shrinkWrap: true,
children: <Widget>[
Padding(
padding: EdgeInsets.only(
left: screenWidth / 12,
right: screenWidth / 12,
top: screenHeight / 30),
child: realmSelector,
),
],
);
}
return Scaffold(
appBar: AppBar(
title: Text('Server Connection Details'),
centerTitle: true),
body: _buildVerticalLayout()
);
}
}
Это то, что мой тестовый сервер Proxmox выдает в результате запроса GET по указанному адресу:
{
"data":[
{
"type":"ad",
"realm":"CELESTIALDATA"
},
{
"type":"pam",
"comment":"Linux PAM standard authentication",
"realm":"pam"
},
{
"type":"pve",
"comment":"Proxmox VE authentication server",
"realm":"pve"
}
]
}
Может кто-нибудь помочь мне понять, что происходит не так? К вашему сведению, я только начал работать с Dart / Flutter несколько дней назад, поэтому я все еще изучаю, как все здесь работает. Я пришел из Java / C ++ / Python фона.
UPDATE:
Я изменил мой клиент в ответ на комментарий Ричарда:
Future<List<AuthRealm>> getAuthRealms() async {
HttpClient client = new HttpClient();
client.badCertificateCallback =((X509Certificate cert, String host, int port) => true);
http.IOClient ioClient = new http.IOClient(client);
final response = await ioClient.get(baseUrl + "access/domains");
print(response.body);
final data = json.decode(response.body);
List<AuthRealm> realms = data.map((j) => AuthRealm.fromJson(j)).toList();
return realms;
}
Однако я все еще получаю сообщение об ошибке, и все, что я вижу, просто не работает.
I/flutter (12950): {"data":[{"type":"ad","realm":"CELESTIALDATA"},{"type":"pve","comment":"Proxmox VE authentication server","realm":"pve"},{"realm":"pam","comment":"Linux PAM standard authentication","type":"pam"}]}
E/flutter (12950): [ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: type '(dynamic) => AuthRealm' is not a subtype of type '(String, dynamic) => MapEntry<dynamic, dynamic>' of 'transform'
E/flutter (12950): #0 Client.getAuthRealms (package:Proxcontrol/Client/client.dart:70:35)
E/flutter (12950): <asynchronous suspension>