feat: web端验证码登录

This commit is contained in:
guozhigq
2024-06-07 23:48:48 +08:00
parent 709e4b4412
commit f8897f74bf
8 changed files with 231 additions and 108 deletions

View File

@ -400,10 +400,12 @@ class Api {
'${HttpString.passBaseUrl}/x/passport-login/captcha?source=main_web';
// web端短信验证码
static const String smsCode =
static const String webSmsCode =
'${HttpString.passBaseUrl}/x/passport-login/web/sms/send';
// web端验证码登录
static const String webSmsLogin =
"${HttpString.passBaseUrl}/x/passport-login/web/login/sms";
// web端密码登录

View File

@ -3,6 +3,7 @@ import 'dart:math';
import 'package:crypto/crypto.dart';
import 'package:dio/dio.dart';
import 'package:encrypt/encrypt.dart';
import 'package:pilipala/http/constants.dart';
import 'package:uuid/uuid.dart';
import '../models/login/index.dart';
import '../utils/login.dart';
@ -21,32 +22,32 @@ class LoginHttp {
}
}
static Future sendSmsCode({
int? cid,
required int tel,
required String token,
required String challenge,
required String validate,
required String seccode,
}) async {
var res = await Request().post(
Api.appSmsCode,
data: {
'cid': cid,
'tel': tel,
"source": "main_web",
'token': token,
'challenge': challenge,
'validate': validate,
'seccode': seccode,
},
options: Options(
contentType: Headers.formUrlEncodedContentType,
// headers: {'user-agent': ApiConstants.userAgent}
),
);
print(res);
}
// static Future sendSmsCode({
// int? cid,
// required int tel,
// required String token,
// required String challenge,
// required String validate,
// required String seccode,
// }) async {
// var res = await Request().post(
// Api.appSmsCode,
// data: {
// 'cid': cid,
// 'tel': tel,
// "source": "main_web",
// 'token': token,
// 'challenge': challenge,
// 'validate': validate,
// 'seccode': seccode,
// },
// options: Options(
// contentType: Headers.formUrlEncodedContentType,
// // headers: {'user-agent': ApiConstants.userAgent}
// ),
// );
// print(res);
// }
// web端验证码
static Future sendWebSmsCode({
@ -60,6 +61,7 @@ class LoginHttp {
Map data = {
'cid': cid,
'tel': tel,
"source": "main_web",
'token': token,
'challenge': challenge,
'validate': validate,
@ -67,17 +69,56 @@ class LoginHttp {
};
FormData formData = FormData.fromMap({...data});
var res = await Request().post(
Api.smsCode,
Api.webSmsCode,
data: formData,
options: Options(
contentType: Headers.formUrlEncodedContentType,
),
);
print(res);
if (res.data['code'] == 0) {
return {
'status': true,
'data': res.data['data'],
};
} else {
return {'status': false, 'data': [], 'msg': res.data['message']};
}
}
// web端验证码登录
static Future loginInByWebSmsCode() async {}
static Future loginInByWebSmsCode({
int? cid,
required int tel,
required int code,
required String captchaKey,
}) async {
// webSmsLogin
Map data = {
"cid": cid,
"tel": tel,
"code": code,
"source": "main_mini",
"keep": 0,
"captcha_key": captchaKey,
"go_url": HttpString.baseUrl
};
FormData formData = FormData.fromMap({...data});
var res = await Request().post(
Api.webSmsLogin,
data: formData,
options: Options(
contentType: Headers.formUrlEncodedContentType,
),
);
if (res.data['code'] == 0) {
return {
'status': true,
'data': res.data['data'],
};
} else {
return {'status': false, 'data': [], 'msg': res.data['message']};
}
}
// web端密码登录
static Future liginInByWebPwd() async {}

View File

@ -1,11 +1,16 @@
import 'dart:async';
import 'dart:developer';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
import 'package:get/get_rx/get_rx.dart';
import 'package:pilipala/http/login.dart';
import 'package:gt3_flutter_plugin/gt3_flutter_plugin.dart';
import 'package:pilipala/models/login/index.dart';
import 'package:pilipala/pages/webview/index.dart';
import 'package:pilipala/utils/login.dart';
class LoginPageController extends GetxController {
final GlobalKey mobFormKey = GlobalKey<FormState>();
@ -26,9 +31,19 @@ class LoginPageController extends GetxController {
final Gt3FlutterPlugin captcha = Gt3FlutterPlugin();
// 倒计时60s
RxInt seconds = 60.obs;
late Timer timer;
RxBool smsCodeSendStatus = false.obs;
// 默认密码登录
RxInt loginType = 0.obs;
late String captchaLey;
late int tel;
late int webSmsCode;
// 监听pageView切换
void onPageChange(int index) {
currentIndex.value = index;
@ -43,6 +58,7 @@ class LoginPageController extends GetxController {
curve: Curves.easeInOut,
);
passwordTextFieldNode.requestFocus();
(mobFormKey.currentState as FormState).save();
}
}
@ -86,18 +102,32 @@ class LoginPageController extends GetxController {
}
}
// 验证码登录
void loginInByCode() {
if ((msgCodeFormKey.currentState as FormState).validate()) {}
// web端验证码登录
void loginInByCode() async {
if ((msgCodeFormKey.currentState as FormState).validate()) {
(msgCodeFormKey.currentState as FormState).save();
var res = await LoginHttp.loginInByWebSmsCode(
cid: 86,
tel: tel,
code: webSmsCode,
captchaKey: captchaLey,
);
if (res['status']) {
log(res.toString());
LoginUtils.confirmLogin('', null);
} else {
SmartDialog.showToast(res['msg']);
}
}
}
// app端验证码
void getMsgCode() async {
// 获取app端验证码
void getAppMsgCode() async {
getCaptcha((data) async {
CaptchaDataModel captchaData = data;
var res = await LoginHttp.sendAppSmsCode(
cid: 86,
tel: 13734077064,
tel: tel,
token: captchaData.token!,
challenge: captchaData.geetest!.challenge!,
validate: captchaData.validate!,
@ -121,7 +151,7 @@ class LoginPageController extends GetxController {
captcha.addEventHandler(onShow: (Map<String, dynamic> message) async {
SmartDialog.dismiss();
}, onClose: (Map<String, dynamic> message) async {
SmartDialog.showToast('关闭验证');
SmartDialog.showToast('取消验证');
}, onResult: (Map<String, dynamic> message) async {
debugPrint("Captcha result: $message");
String code = message["code"];
@ -201,4 +231,40 @@ class LoginPageController extends GetxController {
captcha.startCaptcha(registerData);
} else {}
}
// 获取web端验证码
void getWebMsgCode() async {
getCaptcha((data) async {
CaptchaDataModel captchaData = data;
var res = await LoginHttp.sendWebSmsCode(
cid: 86,
tel: tel,
token: captchaData.token!,
challenge: captchaData.geetest!.challenge!,
validate: captchaData.validate!,
seccode: captchaData.seccode!,
);
if (res['status']) {
captchaLey = res['data']['captcha_key'];
SmartDialog.showToast('验证码已发送');
// 倒计时60s
smsCodeSendStatus.value = true;
startTimer();
} else {
SmartDialog.showToast(res['msg']);
}
});
}
void startTimer() {
timer = Timer.periodic(const Duration(seconds: 1), (timer) {
if (seconds.value > 0) {
seconds.value--;
} else {
seconds.value = 60;
smsCodeSendStatus.value = false;
timer.cancel();
}
});
}
}

View File

@ -93,9 +93,7 @@ class _LoginPageState extends State<LoginPage> {
validator: (v) {
return v!.trim().isNotEmpty ? null : "手机号码不能为空";
},
onSaved: (val) {
print(val);
},
onSaved: (val) => _loginPageCtr.tel = int.parse(val!),
onEditingComplete: () {
_loginPageCtr.nextStep();
},
@ -308,21 +306,28 @@ class _LoginPageState extends State<LoginPage> {
? null
: "验证码不能为空";
},
onSaved: (val) {
print(val);
},
onSaved: (val) => _loginPageCtr.webSmsCode =
int.parse(val!),
),
Positioned(
Obx(() {
return Positioned(
right: 8,
top: 4,
top: 0,
child: Center(
child: TextButton(
onPressed: () =>
_loginPageCtr.getMsgCode(),
child: const Text('获取验证码'),
),
),
onPressed: _loginPageCtr
.smsCodeSendStatus.value
? null
: () =>
_loginPageCtr.getWebMsgCode(),
child: _loginPageCtr
.smsCodeSendStatus.value
? Text(
'重新获取(${_loginPageCtr.seconds.value}s)')
: const Text('获取验证码')),
),
);
})
],
),
),

View File

@ -6,7 +6,6 @@ import 'package:pilipala/http/user.dart';
import 'package:pilipala/models/common/theme_type.dart';
import 'package:pilipala/models/user/info.dart';
import 'package:pilipala/models/user/stat.dart';
import 'package:pilipala/utils/route_push.dart';
import 'package:pilipala/utils/storage.dart';
class MineController extends GetxController {
@ -34,8 +33,8 @@ class MineController extends GetxController {
onLogin() async {
if (!userLogin.value) {
RoutePush.loginPush();
// Get.toNamed('/loginPage');
// RoutePush.loginPush();
Get.toNamed('/loginPage');
} else {
int mid = userInfo.value.mid!;
String face = userInfo.value.face!;

View File

@ -76,7 +76,7 @@ class WebviewController extends GetxController {
(url.startsWith(
'https://passport.bilibili.com/web/sso/exchange_cookie') ||
url.startsWith('https://m.bilibili.com/'))) {
confirmLogin(url);
LoginUtils.confirmLogin(url, controller);
}
},
onWebResourceError: (WebResourceError error) {},
@ -97,54 +97,4 @@ class WebviewController extends GetxController {
)
..loadRequest(Uri.parse(url));
}
confirmLogin(url) async {
var content = '';
if (url != null) {
content = '${content + url}; \n';
}
try {
await SetCookie.onSet();
final result = await UserHttp.userInfo();
if (result['status'] && result['data'].isLogin) {
SmartDialog.showToast('登录成功');
try {
Box userInfoCache = GStrorage.userInfo;
if (!userInfoCache.isOpen) {
userInfoCache = await Hive.openBox('userInfo');
}
await userInfoCache.put('userInfoCache', result['data']);
final HomeController homeCtr = Get.find<HomeController>();
homeCtr.updateLoginStatus(true);
homeCtr.userFace.value = result['data'].face;
final MediaController mediaCtr = Get.find<MediaController>();
mediaCtr.mid = result['data'].mid;
await LoginUtils.refreshLoginStatus(true);
} catch (err) {
SmartDialog.show(builder: (BuildContext context) {
return AlertDialog(
title: const Text('登录遇到问题'),
content: Text(err.toString()),
actions: [
TextButton(
onPressed: () => controller.reload(),
child: const Text('确认'),
)
],
);
});
}
Get.back();
} else {
// 获取用户信息失败
SmartDialog.showToast(result['msg']);
Clipboard.setData(ClipboardData(text: result['msg']));
}
} catch (e) {
SmartDialog.showNotify(msg: e.toString(), notifyType: NotifyType.warning);
content = content + e.toString();
Clipboard.setData(ClipboardData(text: content));
}
}
}

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:pilipala/utils/login.dart';
import 'package:url_launcher/url_launcher.dart';
import 'controller.dart';
import 'package:webview_flutter/webview_flutter.dart';
@ -43,7 +44,8 @@ class _WebviewPageState extends State<WebviewPage> {
Obx(
() => _webviewController.type.value == 'login'
? TextButton(
onPressed: () => _webviewController.confirmLogin(null),
onPressed: () =>
LoginUtils.confirmLogin(null, _webviewController),
child: const Text('刷新登录状态'),
)
: const SizedBox(),

View File

@ -2,12 +2,18 @@ import 'dart:convert';
import 'dart:math';
import 'package:crypto/crypto.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
import 'package:hive/hive.dart';
import 'package:pilipala/http/user.dart';
import 'package:pilipala/pages/dynamics/index.dart';
import 'package:pilipala/pages/home/index.dart';
import 'package:pilipala/pages/media/index.dart';
import 'package:pilipala/pages/mine/index.dart';
import 'package:pilipala/utils/cookie.dart';
import 'package:pilipala/utils/storage.dart';
import 'package:uuid/uuid.dart';
class LoginUtils {
@ -57,4 +63,56 @@ class LoginUtils {
String uuid = getUUID() + getUUID();
return 'XY${uuid.substring(0, 35).toUpperCase()}';
}
static confirmLogin(url, controller) async {
var content = '';
if (url != null) {
content = '${content + url}; \n';
}
try {
await SetCookie.onSet();
final result = await UserHttp.userInfo();
if (result['status'] && result['data'].isLogin) {
SmartDialog.showToast('登录成功');
try {
Box userInfoCache = GStrorage.userInfo;
if (!userInfoCache.isOpen) {
userInfoCache = await Hive.openBox('userInfo');
}
await userInfoCache.put('userInfoCache', result['data']);
final HomeController homeCtr = Get.find<HomeController>();
homeCtr.updateLoginStatus(true);
homeCtr.userFace.value = result['data'].face;
final MediaController mediaCtr = Get.find<MediaController>();
mediaCtr.mid = result['data'].mid;
await LoginUtils.refreshLoginStatus(true);
} catch (err) {
SmartDialog.show(builder: (BuildContext context) {
return AlertDialog(
title: const Text('登录遇到问题'),
content: Text(err.toString()),
actions: [
TextButton(
onPressed: controller != null
? () => controller.reload()
: SmartDialog.dismiss,
child: const Text('确认'),
)
],
);
});
}
Get.back();
} else {
// 获取用户信息失败
SmartDialog.showToast(result['msg']);
Clipboard.setData(ClipboardData(text: result['msg']));
}
} catch (e) {
SmartDialog.showNotify(msg: e.toString(), notifyType: NotifyType.warning);
content = content + e.toString();
Clipboard.setData(ClipboardData(text: content));
}
}
}